@nextclaw/kernel 0.1.2-beta.3 → 0.1.2-beta.5

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.
package/dist/index.d.ts CHANGED
@@ -302,11 +302,13 @@ type AppEventEmitOptions = {
302
302
  };
303
303
  type AppEventHandler<T> = (payload: T, envelope: AppEventEnvelope<T>) => void;
304
304
  type EventBusOptions = {
305
+ onFirstSubscriber?: () => void;
305
306
  onListenerError?: (params: {
306
307
  type: string;
307
308
  payload: unknown;
308
309
  error: unknown;
309
310
  }) => void;
311
+ onNoSubscribers?: () => void;
310
312
  };
311
313
  type ConfigUpdatedEvent = AppEventEnvelope<{
312
314
  path: string;
@@ -373,7 +375,10 @@ type AppEvent = ConfigUpdatedEvent | ChannelConfigApplyStatusEvent | SessionUpda
373
375
  declare class EventBus {
374
376
  private readonly listeners;
375
377
  private readonly globalListeners;
378
+ private listenerCount;
379
+ private readonly onFirstSubscriber?;
376
380
  private readonly onListenerError?;
381
+ private readonly onNoSubscribers?;
377
382
  constructor(options?: EventBusOptions);
378
383
  emit: <T>(key: AppEventKey<T>, payload: T, options?: AppEventEmitOptions) => void;
379
384
  emitEnvelope: <T>(event: AppEventEnvelope<T>) => void;
@@ -381,6 +386,8 @@ declare class EventBus {
381
386
  off: <T>(key: AppEventKey<T>, handler: AppEventHandler<T>) => void;
382
387
  once: <T>(key: AppEventKey<T>, handler: AppEventHandler<T>) => (() => void);
383
388
  subscribeAll: (handler: (event: AppEventEnvelope) => void) => (() => void);
389
+ private registerSubscriber;
390
+ private unregisterSubscriber;
384
391
  private safeInvokeListener;
385
392
  private safeInvokeGlobalListener;
386
393
  }
package/dist/index.js CHANGED
@@ -253,9 +253,14 @@ var NextclawKernel = class {
253
253
  var EventBus = class {
254
254
  listeners = /* @__PURE__ */ new Map();
255
255
  globalListeners = /* @__PURE__ */ new Set();
256
+ listenerCount = 0;
257
+ onFirstSubscriber;
256
258
  onListenerError;
259
+ onNoSubscribers;
257
260
  constructor(options = {}) {
261
+ this.onFirstSubscriber = options.onFirstSubscriber;
258
262
  this.onListenerError = options.onListenerError;
263
+ this.onNoSubscribers = options.onNoSubscribers;
259
264
  }
260
265
  emit = (key, payload, options = {}) => {
261
266
  const envelope = {
@@ -274,8 +279,11 @@ var EventBus = class {
274
279
  };
275
280
  on = (key, handler) => {
276
281
  const listeners = this.listeners.get(key.id) ?? /* @__PURE__ */ new Set();
277
- listeners.add(handler);
282
+ const typedHandler = handler;
283
+ const added = !listeners.has(typedHandler);
284
+ listeners.add(typedHandler);
278
285
  this.listeners.set(key.id, listeners);
286
+ if (added) this.registerSubscriber();
279
287
  return () => {
280
288
  this.off(key, handler);
281
289
  };
@@ -283,8 +291,9 @@ var EventBus = class {
283
291
  off = (key, handler) => {
284
292
  const listeners = this.listeners.get(key.id);
285
293
  if (!listeners) return;
286
- listeners.delete(handler);
294
+ const deleted = listeners.delete(handler);
287
295
  if (listeners.size === 0) this.listeners.delete(key.id);
296
+ if (deleted) this.unregisterSubscriber();
288
297
  };
289
298
  once = (key, handler) => {
290
299
  const wrappedHandler = (payload, envelope) => {
@@ -295,11 +304,21 @@ var EventBus = class {
295
304
  return unsubscribe;
296
305
  };
297
306
  subscribeAll = (handler) => {
307
+ const added = !this.globalListeners.has(handler);
298
308
  this.globalListeners.add(handler);
309
+ if (added) this.registerSubscriber();
299
310
  return () => {
300
- this.globalListeners.delete(handler);
311
+ if (this.globalListeners.delete(handler)) this.unregisterSubscriber();
301
312
  };
302
313
  };
314
+ registerSubscriber = () => {
315
+ this.listenerCount += 1;
316
+ if (this.listenerCount === 1) this.onFirstSubscriber?.();
317
+ };
318
+ unregisterSubscriber = () => {
319
+ this.listenerCount = Math.max(0, this.listenerCount - 1);
320
+ if (this.listenerCount === 0) this.onNoSubscribers?.();
321
+ };
303
322
  safeInvokeListener = (event, listener) => {
304
323
  try {
305
324
  listener(event.payload, event);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/kernel",
3
- "version": "0.1.2-beta.3",
3
+ "version": "0.1.2-beta.5",
4
4
  "private": false,
5
5
  "description": "NextClaw product kernel skeleton for agents, tasks, sessions, context, tools, skills, providers, automation, and channels.",
6
6
  "type": "module",
@@ -20,16 +20,18 @@
20
20
  "dist"
21
21
  ],
22
22
  "dependencies": {
23
- "@nextclaw/ncp": "0.5.6-beta.1"
23
+ "@nextclaw/ncp": "0.5.6-beta.3"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/node": "^20.17.6",
27
27
  "prettier": "^3.3.3",
28
- "typescript": "^5.6.3"
28
+ "typescript": "^5.6.3",
29
+ "vitest": "^4.1.2"
29
30
  },
30
31
  "scripts": {
31
32
  "build": "tsdown src/index.ts src/types/update-contract.types.ts --dts --clean --target es2022 --no-fixedExtension",
32
33
  "lint": "eslint .",
34
+ "test": "vitest run",
33
35
  "tsc": "tsc -p tsconfig.json"
34
36
  }
35
37
  }