Enable LLMs to handle webhooks with plaintext files
1import PQueue from "p-queue";
2import { verifyRequest } from "./verify.js";
3import { renderTemplate } from "./render.js";
4import type { LureCache } from "./loader.js";
5import type { LureRequest } from "./types.js";
6
7interface QueueOptions {
8 cache: LureCache;
9 callback: (prompt: string, config: unknown) => Promise<void>;
10 maxAttempts: number;
11}
12
13export function createQueue(options: QueueOptions): {
14 enqueue(lurePath: string, req: LureRequest): void;
15 drain(): Promise<void>;
16} {
17 const { cache, callback, maxAttempts } = options;
18 const queue = new PQueue({ concurrency: 1 });
19
20 return {
21 enqueue(lurePath: string, req: LureRequest): void {
22 void queue.add(async () => {
23 const lure = cache.get(lurePath);
24 if (lure === undefined) {
25 return;
26 }
27
28 const verified = await verifyRequest(lure, req);
29 if (!verified) {
30 return;
31 }
32
33 const prompt = await renderTemplate(lure, req);
34
35 let lastError: unknown;
36 for (let attempt = 0; attempt < maxAttempts; attempt++) {
37 try {
38 await callback(prompt, lure.frontmatter.config);
39 return;
40 } catch (error) {
41 lastError = error;
42 }
43 }
44
45 console.error(`Callback failed after ${maxAttempts} attempts for ${lurePath}:`, lastError);
46 });
47 },
48
49 drain(): Promise<void> {
50 return queue.onIdle();
51 },
52 };
53}