Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
/**
* DMP-18 / DMP-19 — `ChunkErrorEnvelope` shape and codes;
* `GENERATION_STALE` includes responder generation.
*/
import { describe, expect, it } from "@suaveplan/testing/runner";
import {
DMP_CODES,
DmpError,
decodeErrorPayload,
encodeErrorPayload,
} from "../src/index.js";
import type {
ChunkErrorCode,
ChunkErrorPayload,
} from "../src/types/protocol.types.js";
const FILE_ID = "9".repeat(64);
describe("DMP-18 — ChunkErrorEnvelope shape", () => {
it("every ChunkErrorCode round-trips through envelope encoding", {
timeout: 5000,
}, () => {
const codes: readonly ChunkErrorCode[] = [
"NOT_FOUND",
"ACCESS_DENIED",
"BANDWIDTH_EXCEEDED",
"GENERATION_STALE",
"INTERNAL",
];
for (const code of codes) {
const payload: ChunkErrorPayload = {
fileId: FILE_ID,
correlationId: `req-${code}`,
code,
...(code === "GENERATION_STALE"
? { responderGeneration: 7 }
: {}),
};
const wire = encodeErrorPayload(payload);
const round = decodeErrorPayload(wire);
expect(round.code).toBe(code);
expect(round.correlationId).toBe(`req-${code}`);
}
});
it("rejects malformed wire bytes", { timeout: 5000 }, () => {
try {
decodeErrorPayload(new TextEncoder().encode("not json"));
throw new Error("expected rejection");
} catch (err) {
expect(err).toBeInstanceOf(DmpError);
expect((err as DmpError).code).toBe(DMP_CODES.ENVELOPE_MALFORMED);
}
});
});
describe("DMP-19 — GENERATION_STALE includes responder generation", () => {
it("GENERATION_STALE error includes responder's current generation", {
timeout: 5000,
}, () => {
const wire = encodeErrorPayload({
fileId: FILE_ID,
correlationId: "req-1",
code: "GENERATION_STALE",
responderGeneration: 42,
});
const decoded = decodeErrorPayload(wire);
expect(decoded.responderGeneration).toBe(42);
});
it("GENERATION_STALE without responderGeneration rejected at encode", {
timeout: 5000,
}, () => {
try {
encodeErrorPayload({
fileId: FILE_ID,
correlationId: "req-1",
code: "GENERATION_STALE",
});
throw new Error("expected rejection");
} catch (err) {
expect(err).toBeInstanceOf(DmpError);
expect((err as DmpError).code).toBe(DMP_CODES.ENVELOPE_MALFORMED);
}
});
it("GENERATION_STALE without responderGeneration rejected at decode", {
timeout: 5000,
}, () => {
const wire = new TextEncoder().encode(
JSON.stringify({
fileId: FILE_ID,
correlationId: "req-1",
code: "GENERATION_STALE",
})
);
try {
decodeErrorPayload(wire);
throw new Error("expected rejection");
} catch (err) {
expect(err).toBeInstanceOf(DmpError);
expect((err as DmpError).code).toBe(DMP_CODES.ENVELOPE_MALFORMED);
}
});
it("optional retryAfterMs field round-trips", { timeout: 5000 }, () => {
const wire = encodeErrorPayload({
fileId: FILE_ID,
correlationId: "req-2",
code: "BANDWIDTH_EXCEEDED",
retryAfterMs: 5_000,
});
const decoded = decodeErrorPayload(wire);
expect(decoded.retryAfterMs).toBe(5_000);
});
});