@minesa-org/mini-interaction 0.2.22 → 0.2.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1588,13 +1588,16 @@ function resolveOAuthConfig(provided) {
1588
1588
  }
1589
1589
  /**
1590
1590
  * Wraps a handler function with timeout detection and error handling.
1591
+ *
1592
+ * CRITICAL FOR HTTP INTERACTIONS:
1593
+ * When deferReply() is called, we MUST return the ACK to Discord immediately.
1594
+ * The handler continues executing and sends follow-up via webhook.
1595
+ * The ACK must reach Discord before any webhook PATCH requests can succeed.
1591
1596
  */
1592
1597
  function createTimeoutWrapper(handler, timeoutMs, handlerName, enableWarnings = true, ackPromise) {
1593
1598
  return async (...args) => {
1594
1599
  const startTime = Date.now();
1595
1600
  let timeoutId;
1596
- let ackResult = null;
1597
- let ackReceived = false;
1598
1601
  const timeoutPromise = new Promise((_, reject) => {
1599
1602
  timeoutId = setTimeout(() => {
1600
1603
  const elapsed = Date.now() - startTime;
@@ -1602,55 +1605,54 @@ function createTimeoutWrapper(handler, timeoutMs, handlerName, enableWarnings =
1602
1605
  reject(new Error(`Handler timeout: ${handlerName} exceeded ${timeoutMs}ms limit`));
1603
1606
  }, timeoutMs);
1604
1607
  });
1605
- // If we have an ackPromise, listen for it but DON'T return early
1606
- // Instead, capture the ACK result and continue waiting for handler
1608
+ // Start handler execution immediately (don't await yet)
1609
+ const handlerPromise = Promise.resolve(handler(...args));
1610
+ // If we have an ackPromise, race between ACK and timeout
1611
+ // When ACK is received, return IMMEDIATELY so Discord gets the response
1612
+ // Handler continues in background
1607
1613
  if (ackPromise) {
1608
- ackPromise.then((result) => {
1609
- ackResult = result;
1610
- ackReceived = true;
1611
- // Clear the timeout once we have an ACK - handler can now take longer
1614
+ try {
1615
+ const ackResult = await Promise.race([
1616
+ ackPromise,
1617
+ timeoutPromise,
1618
+ ]);
1619
+ // ACK received! Clear timeout and return immediately
1612
1620
  if (timeoutId) {
1613
1621
  clearTimeout(timeoutId);
1614
- timeoutId = undefined;
1615
1622
  }
1616
- }).catch(() => {
1617
- // ACK promise rejection is fine, we'll use handler result
1618
- });
1623
+ // Handler continues in background - attach error handler
1624
+ handlerPromise.catch((error) => {
1625
+ console.error(`[MiniInteraction] ${handlerName} background execution failed:`, error instanceof Error ? error.message : String(error));
1626
+ });
1627
+ return ackResult;
1628
+ }
1629
+ catch (error) {
1630
+ // Timeout occurred before ACK - fall through to check handler
1631
+ if (timeoutId) {
1632
+ clearTimeout(timeoutId);
1633
+ }
1634
+ throw error;
1635
+ }
1619
1636
  }
1637
+ // No ACK promise - wait for handler with timeout
1620
1638
  try {
1621
- // ALWAYS wait for handler to complete
1622
1639
  const handlerResult = await Promise.race([
1623
- handler(...args),
1640
+ handlerPromise,
1624
1641
  timeoutPromise,
1625
1642
  ]);
1626
1643
  if (timeoutId) {
1627
1644
  clearTimeout(timeoutId);
1628
1645
  }
1629
1646
  const elapsed = Date.now() - startTime;
1630
- if (enableWarnings && elapsed > timeoutMs * 0.8 && !ackReceived) {
1647
+ if (enableWarnings && elapsed > timeoutMs * 0.8) {
1631
1648
  console.warn(`[MiniInteraction] ${handlerName} completed in ${elapsed}ms (${Math.round((elapsed / timeoutMs) * 100)}% of timeout limit)`);
1632
1649
  }
1633
- // If we got an ACK, return that for the HTTP response
1634
- // The handler has completed at this point so all background work is done
1635
- if (ackReceived && ackResult !== null) {
1636
- return ackResult;
1637
- }
1638
1650
  return handlerResult;
1639
1651
  }
1640
1652
  catch (error) {
1641
1653
  if (timeoutId) {
1642
1654
  clearTimeout(timeoutId);
1643
1655
  }
1644
- // If handler timed out but we have an ACK, return the ACK
1645
- // This allows deferReply to work even if later operations are slow
1646
- if (error instanceof Error && error.message.includes("Handler timeout")) {
1647
- if (ackReceived && ackResult !== null) {
1648
- console.warn(`[MiniInteraction] ${handlerName} timed out but ACK was already captured. ` +
1649
- `Background work may not complete in serverless environments.`);
1650
- return ackResult;
1651
- }
1652
- throw error;
1653
- }
1654
1656
  console.error(`[MiniInteraction] ${handlerName} failed:`, error);
1655
1657
  throw error;
1656
1658
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minesa-org/mini-interaction",
3
- "version": "0.2.22",
3
+ "version": "0.2.23",
4
4
  "description": "Mini interaction, connecting your app with Discord via HTTP-interaction (Vercel support).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",