Files
nanoclaw/src/response-registry.ts
gavrielc 626c565a70 fix(modules): break circular import TDZ between index.ts and modules
PR #3 introduced a circular-import temporal-dead-zone bug that didn't
surface in unit tests but crashed the service at startup:

  src/index.ts imports './modules/index.js' for side effects
  → src/modules/interactive/index.ts calls registerResponseHandler()
  → that function is declared in src/index.ts
  → but src/index.ts's const responseHandlers = [] hasn't been
    initialized yet (we're in the middle of its module-init)
  → ReferenceError: Cannot access 'responseHandlers' before initialization

Same issue for registerResponseHandler itself (the function reference
resolves to undefined) and for onShutdown in the approvals module.

Caught when the operator started the service and systemd flagged the
process as crashing in auto-restart loop.

Fix: extract responseHandlers + registerResponseHandler + shutdownCallbacks
+ onShutdown into src/response-registry.ts, which has no dependencies on
src/index.ts or on modules. index.ts re-exports the same surface for any
existing consumers; modules import directly from response-registry.js.

The bug was latent because:
- Unit tests import pieces, never src/index.ts's main() flow.
- Host builds clean because TypeScript doesn't catch runtime circular
  init order.
- Only surfaces when the ES module loader actually executes src/index.ts
  as the entry point.

Verified: service boots on Linux host with approvals + interactive
loaded; OneCLI handler starts via onDeliveryAdapterReady callback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 15:48:43 +03:00

46 lines
1.4 KiB
TypeScript

/**
* Response handler + shutdown callback registries.
*
* Extracted from index.ts so that modules calling `registerResponseHandler()`
* or `onShutdown()` at import time don't hit a TDZ error on the const-array
* declarations. index.ts imports src/modules/index.js for its side effects,
* which triggers module registrations that would otherwise happen before
* index.ts's own const initializers have run.
*
* Keep this file dependency-free (log.js is fine, but nothing from
* modules/* or index.ts itself). Any file imported here must not in turn
* import from src/index.ts, or the cycle returns.
*/
export interface ResponsePayload {
questionId: string;
value: string;
userId: string | null;
channelType: string;
platformId: string;
threadId: string | null;
}
export type ResponseHandler = (payload: ResponsePayload) => Promise<boolean>;
const responseHandlers: ResponseHandler[] = [];
export function registerResponseHandler(handler: ResponseHandler): void {
responseHandlers.push(handler);
}
export function getResponseHandlers(): readonly ResponseHandler[] {
return responseHandlers;
}
type ShutdownCallback = () => void | Promise<void>;
const shutdownCallbacks: ShutdownCallback[] = [];
export function onShutdown(cb: ShutdownCallback): void {
shutdownCallbacks.push(cb);
}
export function getShutdownCallbacks(): readonly ShutdownCallback[] {
return shutdownCallbacks;
}