Skip to content

Commit fc40f33

Browse files
committed
fix(webhooks): ack io-bridge webhook deliveries immediately
The io server's HTTP bridge holds the webhook sender's response open until a client answers the callback pid or a 5s timeout fires. The stripe/kofi/bmac/ fourthwall branches never answered it: early returns skip the generic tail ack, and the success paths reassign data, dropping data.get before it is checked. Every delivery therefore took the full 5 seconds to be acknowledged, which is the likely trigger for sender-side retries (the duplicate deliveries the message_id dedup absorbs). Ack at the top of each webhook branch so senders get a sub-second response; data.get is cleared to keep the tail ack from double-answering. The server's resolveCallback is guarded, so a late ack after its timeout is a no-op.
1 parent 21377b9 commit fc40f33

1 file changed

Lines changed: 19 additions & 0 deletions

File tree

background.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9434,6 +9434,21 @@ function isDuplicateInboundWebhook(provider, webhookId) {
94349434
return false;
94359435
}
94369436

9437+
// The io HTTP bridge holds the webhook sender's HTTP response open until a client
9438+
// answers the callback pid (or its 5s timeout fires); ack before processing so
9439+
// senders like Ko-fi get a fast response and don't time out and retry the delivery.
9440+
function ackInboundWebhookDelivery(socket, data) {
9441+
if (!data || !data.get) {
9442+
return;
9443+
}
9444+
try {
9445+
if (socket && socket.readyState === WebSocket.OPEN) {
9446+
socket.send(JSON.stringify({ callback: { get: data.get, result: true } }));
9447+
}
9448+
} catch (e) {}
9449+
data.get = false;
9450+
}
9451+
94379452
const STREAM_DECK_SOURCE_RESPONSE_FIELDS = ["id", "target", "tabId", "username", "videoId", "connectionMode", "activeConnectionMode", "status", "isVisible", "isMuted", "autoActivate", "groupId"];
94389453

94399454
function sanitizeStreamDeckSourceResponse(source) {
@@ -9892,6 +9907,7 @@ function setupSocket() {
98929907
console.error(e);
98939908
}
98949909
} else if ("stripe" in data) {
9910+
ackInboundWebhookDelivery(socketserver, data);
98959911
try {
98969912
if (data.stripe.type !== "checkout.session.completed") {
98979913
return false;
@@ -10054,6 +10070,7 @@ function setupSocket() {
1005410070
return;
1005510071
}
1005610072
} else if ("kofi" in data) {
10073+
ackInboundWebhookDelivery(socketserver, data);
1005710074
try {
1005810075
if (!data.kofi.data) {
1005910076
return false;
@@ -10133,6 +10150,7 @@ function setupSocket() {
1013310150
return;
1013410151
}
1013510152
} else if ("bmac" in data) {
10153+
ackInboundWebhookDelivery(socketserver, data);
1013610154
// Buy Me a Coffe New Membership and Donation detection
1013710155
try {
1013810156
if (!data.bmac) {
@@ -10208,6 +10226,7 @@ function setupSocket() {
1020810226
return;
1020910227
}
1021010228
} else if ("fourthwall" in data) {
10229+
ackInboundWebhookDelivery(socketserver, data);
1021110230
// Dorthwall
1021210231
try {
1021310232
if (!data.fourthwall.data || data.fourthwall.type !== "ORDER_PLACED") {

0 commit comments

Comments
 (0)