/*
RFC-0176: verify the inbound/queue runtime — authenticateInbound, IntegrationEventSchema,
routeEventToReady (self-enabling Lagebild route), and consumeIntegrationBatch dedup via a KV-backed
seen-set. fetch + KV are stubbed so the full producer→consumer flow is exercised without Cloudflare.
- Do not hit the network — fetch is stubbed.
- RFC-0176: initial queue/inbound runtime test.
- RFC-1311: carried legacy entry — Lagebild replaced Pipedrive as sole CRM destination — test updated accordingly.
*/
import { test, expect, afterEach, beforeEach } from "vitest";
import {
IntegrationEventSchema,
authenticateInbound,
consumeIntegrationBatch,
kvDedup,
routeEventToReady,
type IntegrationEvent,
type IntegrationSecrets,
type KvDedupStore,
} from "../index.ts";
const SECRETS: IntegrationSecrets = {
LAGEBILD_API_URL: "https://lagebild-api.example.workers.dev",
LAGEBILD_API_KEY: "lbk_test_key_0001",
LAGEBILD_TENANT_ID: "ten_warpgogol000001",
LAGEBILD_SOURCE_SYSTEM_ID: "site_warpgogol_com",
};
const EVENT: IntegrationEvent = {
eventId: "evt-1",
kind: "lead",
source: "uchat",
locale: "de",
occurredAt: "2026-06-08T00:00:00.000Z",
contact: { name: "Max", email: "max@example.org" },
payload: { note: "Hello from the chat" },
};
/** In-memory KV implementing the dedup store contract. */
function memoryKv(): KvDedupStore & { size(): number } {
const map = new Map();
return {
async get(key) {
return map.has(key) ? (map.get(key) ?? null) : null;
},
async put(key, value) {
map.set(key, value);
},
size: () => map.size,
};
}
let fetchCalls: string[] = [];
const realFetch = globalThis.fetch;
beforeEach(() => {
fetchCalls = [];
// Stub Lagebild ingress endpoint — returns accepted with a submission id.
globalThis.fetch = (async (url: string | URL | Request) => {
fetchCalls.push(String(url));
return {
ok: true,
status: 200,
json: async () => ({
submission_id: "sub_test123",
accepted: true,
is_replay: false,
correlation_id: null,
}),
} as unknown as Response;
}) as typeof fetch;
});
afterEach(() => {
globalThis.fetch = realFetch;
});
test("routeEventToReady routes a lead to the lagebild gogol-adapter destination", async () => {
const result = await routeEventToReady(EVENT, SECRETS);
expect(result.routed).toEqual(["crm:lagebild"]);
expect(result.failed.length).toBe(0);
// lagebild adapter performs a single POST to /v1/ingress.
expect(fetchCalls.length).toBe(1);
});
test("routeEventToReady skips when destination secrets are absent", async () => {
const result = await routeEventToReady(EVENT, {});
expect(result.skipped).toEqual(["crm:lagebild"]);
expect(result.routed.length).toBe(0);
expect(fetchCalls.length).toBe(0);
});
test("consumeIntegrationBatch dedups a queue redelivery via KV (no double-write)", async () => {
const kv = memoryKv();
const dedup = kvDedup(kv);
const first = await consumeIntegrationBatch([EVENT], SECRETS, dedup);
expect(first[0].routed).toEqual(["crm:lagebild"]);
const afterFirst = fetchCalls.length;
expect(afterFirst).toBe(1);
// Redeliver the SAME eventId — must be skipped by dedup, no new fetches.
const second = await consumeIntegrationBatch([EVENT], SECRETS, dedup);
expect(second[0].skipped).toEqual(["crm:lagebild"]);
expect(fetchCalls.length).toBe(afterFirst);
expect(kv.size()).toBe(1);
});
test("authenticateInbound is fail-closed (bearer + header, unset secret rejects)", () => {
const ok = new Headers({ authorization: "Bearer s3cret" });
const okHeader = new Headers({ "x-integration-secret": "s3cret" });
const wrong = new Headers({ authorization: "Bearer nope" });
expect(authenticateInbound(ok, "s3cret")).toBe(true);
expect(authenticateInbound(okHeader, "s3cret")).toBe(true);
expect(authenticateInbound(wrong, "s3cret")).toBe(false);
expect(authenticateInbound(ok, undefined)).toBe(false);
expect(authenticateInbound(new Headers(), "s3cret")).toBe(false);
});
test("IntegrationEventSchema rejects malformed payloads", () => {
expect(IntegrationEventSchema.safeParse(EVENT).success).toBe(true);
expect(IntegrationEventSchema.safeParse({ ...EVENT, kind: "bogus" }).success).toBe(false);
expect(IntegrationEventSchema.safeParse({ ...EVENT, eventId: "" }).success).toBe(false);
expect(IntegrationEventSchema.safeParse({}).success).toBe(false);
});