Skip to content

fix: internal hooks handlers stored in globalThis to survive bundle chunk boundaries#30631

Closed
kevinWangSheng wants to merge 1 commit intoopenclaw:mainfrom
kevinWangSheng:fix/30624-internal-hooks-globalthis
Closed

fix: internal hooks handlers stored in globalThis to survive bundle chunk boundaries#30631
kevinWangSheng wants to merge 1 commit intoopenclaw:mainfrom
kevinWangSheng:fix/30624-internal-hooks-globalthis

Conversation

@kevinWangSheng
Copy link
Copy Markdown
Contributor

Summary

Fixes #30624 - Internal hook message:sent never fires due to split handlers Map between bundle chunks.

Root Cause

The internal hook system (handlers Map, registerInternalHook, triggerInternalHook) was defined as a module-level variable. When bundled into multiple chunks, each chunk got its own handlers Map instance, causing hooks registered in one chunk to be invisible to triggers in another chunk.

Solution

Store the handlers Map in globalThis (globalThis.__openclawHookHandlers) to ensure a single shared instance across all bundle chunks.

Testing

  • All 29 existing internal-hooks tests pass

@openclaw-barnacle openclaw-barnacle bot added channel: discord Channel integration: discord channel: nextcloud-talk Channel integration: nextcloud-talk channel: slack Channel integration: slack channel: telegram Channel integration: telegram channel: whatsapp-web Channel integration: whatsapp-web docker Docker and sandbox tooling agents Agent runtime and tooling channel: feishu Channel integration: feishu size: M trusted-contributor labels Mar 1, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1091feff0d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

* Response behavior when an unpaired (unauthorized) user sends a message.
* @default "silent"
*/
unpairedResponse?: UnpairedResponseMode;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add unpairedResponse to ChannelsSchema defaults

channels.defaults.unpairedResponse is introduced here, but the runtime schema still rejects it because ChannelsSchema.defaults is .strict() with only groupPolicy and heartbeat allowed (src/config/zod-schema.providers.ts:27-33). That means any config trying to set unpairedResponse fails validation, so operators cannot enable code-only/branded; the code then always falls back to "silent" in getUnpairedResponseMode (src/pairing/unpaired-response.ts:10).

Useful? React with 👍 / 👎.

const dmAuthorized = await enforceTelegramDmAccess({
isGroup: event.isGroup,
dmPolicy,
unpairedResponse: getUnpairedResponseMode(loadConfig()),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Respect Telegram unpairedResponse account overrides

This call path always resolves DM pairing response mode from global defaults via getUnpairedResponseMode(loadConfig()), which reads only channels.defaults (src/pairing/unpaired-response.ts:10) and ignores the newly added channels.telegram(...).unpairedResponse field documented in src/config/types.telegram.ts:157-164. As a result, Telegram/account-level overrides never take effect in DM access checks, so per-account policy tuning is broken.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 1, 2026

Greptile Summary

This PR addresses the internal hook message:sent firing issue by storing the handlers Map in globalThis.__openclawHookHandlers to survive bundle chunk boundaries. The core fix is correct and well-tested (all 29 existing internal-hooks tests pass).

Major concern: This PR bundles multiple unrelated changes together, which violates single-responsibility principles and makes it difficult to review, test, and potentially rollback individual changes:

  • Internal hooks fix (main purpose)
  • Telegram removeAckAfterReply functionality (8410f10c)
  • HTTP 402 rate limit handling (72654443)
  • Dockerfile permission fixes (214a2ac3)
  • Feishu target normalization (ba916bde)
  • Unpaired response modes (3f309edd, 19b93dcf)
  • Provider headers injection (76ef433d)
  • Sandbox fs-bridge allowMissingTarget changes (43ede436, 20e0c26a)
  • Memory proxy env vars (080e3a08)
  • Plugin SDK exports (6c405365)

Recommendation: Consider splitting this into separate PRs, with each addressing a single concern. This would make the changes easier to review, test independently, and rollback if issues arise.

Code quality: The individual changes are well-implemented with appropriate tests. The globalThis approach for the internal hooks fix is correct for the use case, though type safety could be improved with a proper declare global block.

Confidence Score: 3/5

  • This PR is moderately safe to merge - individual changes are well-tested, but the bundled nature increases risk
  • Score reflects that while each individual change appears correct and well-tested (internal hooks fix, HTTP 402 handling, sandbox improvements all have tests), bundling 10+ unrelated fixes together makes it difficult to verify all interactions and increases rollback complexity if any single change causes issues in production
  • No individual files have critical issues, but the PR scope itself needs attention - consider splitting into focused PRs

Last reviewed commit: 1091fef

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

27 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +115 to +120
if (!globalThis.__openclawHookHandlers) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).__openclawHookHandlers = new Map<string, InternalHookHandler[]>();
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (globalThis as any).__openclawHookHandlers;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a proper type declaration for the global property instead of using as any:

declare global {
  var __openclawHookHandlers: Map<string, InternalHookHandler[]> | undefined;
}

This provides better type safety while still allowing the property to be undefined initially.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/hooks/internal-hooks.ts
Line: 115-120

Comment:
Consider adding a proper type declaration for the global property instead of using `as any`:

```typescript
declare global {
  var __openclawHookHandlers: Map<string, InternalHookHandler[]> | undefined;
}
```

This provides better type safety while still allowing the property to be undefined initially.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@kevinWangSheng kevinWangSheng force-pushed the fix/30624-internal-hooks-globalthis branch from 1091fef to efb4c55 Compare March 2, 2026 15:34
@openclaw-barnacle openclaw-barnacle bot added size: XS and removed channel: discord Channel integration: discord channel: nextcloud-talk Channel integration: nextcloud-talk channel: slack Channel integration: slack channel: telegram Channel integration: telegram channel: whatsapp-web Channel integration: whatsapp-web docker Docker and sandbox tooling agents Agent runtime and tooling channel: feishu Channel integration: feishu size: M labels Mar 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Internal hook message:sent never fires due to split handlers Map between bundle chunks

2 participants