@kuindji/reactive 1.0.21 → 1.0.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.
package/README.md CHANGED
@@ -117,29 +117,28 @@ type ApplicationData = {
117
117
  type: string;
118
118
  message: string;
119
119
  }[];
120
- }
121
- const event = createEvent(<() => Partial<ApplicationData>>);
120
+ };
121
+ const event = createEvent<() => Partial<ApplicationData>>();
122
122
  event.addListener(() => {
123
123
  return {
124
124
  user: {
125
125
  username: "john",
126
126
  role: "admin",
127
- loggedIn: true
128
- }
129
- }
127
+ loggedIn: true,
128
+ },
129
+ };
130
130
  });
131
131
  event.addListener(() => {
132
132
  return {
133
133
  notifications: [
134
134
  {
135
135
  type: "chat",
136
- message: "You've got a new message!"
137
- }
138
- ]
139
- }
136
+ message: "You've got a new message!",
137
+ },
138
+ ],
139
+ };
140
140
  });
141
141
 
142
-
143
142
  const applicationData = event.merge();
144
143
  ```
145
144
 
package/dist/action.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ApiType, BaseHandler, ErrorListenerSignature, ErrorResponse } from "./lib/types";
2
- export type ActionResponse<Response extends any = any, Args extends any[] = any[]> = {
2
+ export type ActionResponse<Response = any, Args extends unknown[] = unknown[]> = {
3
3
  response: Response;
4
4
  error: null;
5
5
  args: Args;
package/dist/actionBus.js CHANGED
@@ -7,9 +7,7 @@ function createActionBus(initialActions = {}, errorListener) {
7
7
  const actions = new Map();
8
8
  const errorEvent = (0, event_1.createEvent)();
9
9
  if (errorListener) {
10
- errorEvent.addListener(({ error, args }) => {
11
- errorEvent.emit({ error, args, type: "action" });
12
- });
10
+ errorEvent.addListener(errorListener);
13
11
  }
14
12
  const add = (name, action) => {
15
13
  if (!actions.has(name)) {
@@ -28,6 +26,9 @@ function createActionBus(initialActions = {}, errorListener) {
28
26
  };
29
27
  const invoke = (name, ...args) => {
30
28
  const action = get(name);
29
+ if (!action) {
30
+ throw new Error(`Action ${name} not found`);
31
+ }
31
32
  return action.invoke(...args);
32
33
  };
33
34
  const on = (name, handler, options) => {
package/dist/event.d.ts CHANGED
@@ -118,7 +118,7 @@ export declare function createEvent<ListenerSignature extends BaseHandler>(event
118
118
  readonly reset: () => void;
119
119
  readonly isSuspended: () => boolean;
120
120
  readonly isQueued: () => boolean;
121
- readonly withTags: <T extends (...args: any[]) => any>(tags: string[], callback: T) => ReturnType<T>;
121
+ readonly withTags: <R>(tags: string[], callback: () => R) => R;
122
122
  readonly promise: (options?: ListenerOptions) => Promise<Parameters<ListenerSignature>>;
123
123
  readonly first: (...args: Parameters<ListenerSignature>) => ReturnType<ListenerSignature> | undefined;
124
124
  readonly resolveFirst: (...args: Parameters<ListenerSignature>) => Promise<Awaited<ReturnType<ListenerSignature>> | undefined>;
package/dist/event.js CHANGED
@@ -7,7 +7,7 @@ const tagsIntersect_1 = require("./lib/tagsIntersect");
7
7
  const types_1 = require("./lib/types");
8
8
  function createEvent(eventOptions = {}) {
9
9
  let listeners = [];
10
- let errorListeners = [];
10
+ const errorListeners = [];
11
11
  let queue = [];
12
12
  let suspended = false;
13
13
  let queued = false;
@@ -116,7 +116,7 @@ function createEvent(eventOptions = {}) {
116
116
  }
117
117
  };
118
118
  const addErrorListener = (handler, context) => {
119
- if (listeners.find((l) => l.handler === handler && l.context === context)) {
119
+ if (errorListeners.find((l) => l.handler === handler && l.context === context)) {
120
120
  return;
121
121
  }
122
122
  errorListeners.push({ handler, context });
@@ -152,10 +152,14 @@ function createEvent(eventOptions = {}) {
152
152
  const isQueued = () => queued;
153
153
  const reset = () => {
154
154
  listeners.length = 0;
155
+ errorListeners.length = 0;
155
156
  queue.length = 0;
156
157
  suspended = false;
157
158
  queued = false;
158
159
  triggered = 0;
160
+ lastTrigger = null;
161
+ sortListeners = false;
162
+ cachedPromise = null;
159
163
  };
160
164
  const _listenerCall = (listener, args, resolve = null) => {
161
165
  let isAsync = listener.async;
@@ -174,7 +178,20 @@ function createEvent(eventOptions = {}) {
174
178
  : listener.handler.bind(listener.context)(...args);
175
179
  if (resolve !== null) {
176
180
  if (result instanceof Promise) {
177
- result.then(resolve);
181
+ void result.then(resolve).catch((error) => {
182
+ for (const errorListener of errorListeners) {
183
+ errorListener.handler({
184
+ error: error instanceof Error
185
+ ? error
186
+ : new Error(error),
187
+ args: args,
188
+ type: "event",
189
+ });
190
+ }
191
+ if (errorListeners.length === 0) {
192
+ throw error;
193
+ }
194
+ });
178
195
  }
179
196
  else {
180
197
  resolve(result);
@@ -287,7 +304,7 @@ function createEvent(eventOptions = {}) {
287
304
  continue;
288
305
  }
289
306
  if (isConsequent && results.length > 0) {
290
- let prev = results[results.length - 1];
307
+ const prev = results[results.length - 1];
291
308
  if (hasPromises) {
292
309
  const prevPromise = prev instanceof Promise
293
310
  ? prev
@@ -360,13 +377,13 @@ function createEvent(eventOptions = {}) {
360
377
  }
361
378
  case types_1.TriggerReturnType.CONCAT: {
362
379
  return hasPromises
363
- ? Promise.all(results).then((results) => results.flat())
380
+ ? Promise.all(results).then((r) => r.flat())
364
381
  : results.flat();
365
382
  }
366
383
  case types_1.TriggerReturnType.MERGE: {
367
384
  return hasPromises
368
- ? Promise.all(results).then((results) => Object.assign.apply(null, [{}, ...results]))
369
- : Object.assign.apply(null, [{}, ...results]);
385
+ ? Promise.all(results).then((r) => Object.assign({}, ...r))
386
+ : Object.assign({}, ...results);
370
387
  }
371
388
  case types_1.TriggerReturnType.LAST: {
372
389
  return results.pop();
@@ -378,7 +395,9 @@ function createEvent(eventOptions = {}) {
378
395
  return;
379
396
  }
380
397
  case types_1.TriggerReturnType.FIRST_NON_EMPTY: {
381
- return Promise.all(results).then((results) => results.find((r) => r !== undefined && r !== null));
398
+ return hasPromises
399
+ ? Promise.all(results).then((r) => r.find((item) => item !== undefined && item !== null))
400
+ : results.find((item) => item !== undefined && item !== null);
382
401
  }
383
402
  case types_1.TriggerReturnType.PIPE: {
384
403
  return results[results.length - 1];
@@ -390,16 +409,24 @@ function createEvent(eventOptions = {}) {
390
409
  };
391
410
  const withTags = (tags, callback) => {
392
411
  currentTagsFilter = tags;
393
- const result = callback();
394
- currentTagsFilter = null;
395
- return result;
412
+ try {
413
+ return callback();
414
+ }
415
+ finally {
416
+ currentTagsFilter = null;
417
+ }
396
418
  };
419
+ let cachedPromise = null;
397
420
  const promise = (options) => {
398
- return new Promise((resolve) => {
399
- options = Object.assign(Object.assign({}, (options || {})), { limit: 1 });
400
- const l = ((...args) => resolve(args));
401
- addListener(l, options);
402
- });
421
+ return cachedPromise = cachedPromise
422
+ || new Promise((resolve) => {
423
+ options = Object.assign(Object.assign({}, (options || {})), { limit: 1 });
424
+ const l = ((...args) => {
425
+ resolve(args);
426
+ cachedPromise = null;
427
+ });
428
+ addListener(l, options);
429
+ });
403
430
  };
404
431
  const first = (...args) => {
405
432
  return _trigger(args, types_1.TriggerReturnType.FIRST);
@@ -66,25 +66,25 @@ export declare function createEventBus<EventsMap extends BaseEventMap = DefaultE
66
66
  readonly dispatch: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => void;
67
67
  readonly get: <K extends KeyOf<GetEventsMap<EventsMap>>>(name: K) => GetEventTypesMap<EventsMap>[K];
68
68
  readonly add: (name: MapKey, options?: EventOptions<BaseHandler>) => void;
69
- readonly first: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => ReturnType<EventsMap[K]> | undefined>;
70
- readonly resolveFirst: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => Promise<Awaited<ReturnType<EventsMap[K]>> | undefined>>;
71
- readonly all: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => ReturnType<EventsMap[K]>[]>;
72
- readonly resolveAll: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => Promise<Awaited<ReturnType<EventsMap[K]>>[]>>;
73
- readonly resolve: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => Promise<Awaited<ReturnType<EventsMap[K]>>[]>>;
74
- readonly last: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => ReturnType<EventsMap[K]> | undefined>;
75
- readonly resolveLast: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => Promise<Awaited<ReturnType<EventsMap[K]>> | undefined>>;
76
- readonly merge: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => ReturnType<EventsMap[K]> | undefined>;
77
- readonly resolveMerge: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => Promise<Awaited<ReturnType<EventsMap[K]>> | undefined>>;
78
- readonly concat: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => (ReturnType<EventsMap[K]> extends infer T ? T extends ReturnType<EventsMap[K]> ? T extends (infer U)[] ? U : T : never : never)[]>;
79
- readonly resolveConcat: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => Promise<(Awaited<ReturnType<EventsMap[K]>> extends infer T ? T extends Awaited<ReturnType<EventsMap[K]>> ? T extends (infer U)[] ? U : T : never : never)[]>>;
80
- readonly firstNonEmpty: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => ReturnType<EventsMap[K]> | undefined>;
81
- readonly resolveFirstNonEmpty: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => Promise<Awaited<ReturnType<EventsMap[K]>> | undefined>>;
82
- readonly untilTrue: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => void>;
83
- readonly untilFalse: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => void>;
84
- readonly pipe: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => ReturnType<EventsMap[K]> | undefined>;
85
- readonly resolvePipe: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => Promise<Awaited<ReturnType<EventsMap[K]>> | undefined>>;
86
- readonly raw: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => (ReturnType<EventsMap[K]> extends infer T ? T extends ReturnType<EventsMap[K]> ? T extends (infer U)[] ? U : T : never : never)[]>;
87
- readonly withTags: <T extends (...args: any[]) => any>(tags: string[], callback: T) => ReturnType<T>;
69
+ readonly first: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["first"]>;
70
+ readonly resolveFirst: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveFirst"]>;
71
+ readonly all: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["all"]>;
72
+ readonly resolveAll: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveAll"]>;
73
+ readonly resolve: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveAll"]>;
74
+ readonly last: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["last"]>;
75
+ readonly resolveLast: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveLast"]>;
76
+ readonly merge: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["merge"]>;
77
+ readonly resolveMerge: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveMerge"]>;
78
+ readonly concat: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["concat"]>;
79
+ readonly resolveConcat: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveConcat"]>;
80
+ readonly firstNonEmpty: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["firstNonEmpty"]>;
81
+ readonly resolveFirstNonEmpty: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveFirstNonEmpty"]>;
82
+ readonly untilTrue: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["untilTrue"]>;
83
+ readonly untilFalse: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["untilFalse"]>;
84
+ readonly pipe: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["pipe"]>;
85
+ readonly resolvePipe: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolvePipe"]>;
86
+ readonly raw: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["raw"]>;
87
+ readonly withTags: <R>(tags: string[], callback: () => R) => R;
88
88
  readonly intercept: (fn: InterceptorFunction) => void;
89
89
  readonly stopIntercepting: () => void;
90
90
  readonly isIntercepting: () => boolean;
@@ -94,14 +94,14 @@ export declare function createEventBus<EventsMap extends BaseEventMap = DefaultE
94
94
  readonly relay: ({ eventSource, remoteEventName, localEventName, proxyType, localEventNamePrefix, }: {
95
95
  eventSource: RelaySource;
96
96
  remoteEventName: MapKey;
97
- localEventName?: any;
97
+ localEventName?: MapKey | null;
98
98
  proxyType?: ProxyType;
99
99
  localEventNamePrefix?: string | null;
100
100
  }) => void;
101
101
  readonly unrelay: ({ eventSource, remoteEventName, localEventName, proxyType, localEventNamePrefix, }: {
102
102
  eventSource: RelaySource;
103
103
  remoteEventName: MapKey;
104
- localEventName?: any;
104
+ localEventName?: MapKey | null;
105
105
  proxyType?: ProxyType;
106
106
  localEventNamePrefix?: string | null;
107
107
  }) => void;
package/dist/eventBus.js CHANGED
@@ -87,35 +87,46 @@ function createEventBus(eventBusOptions) {
87
87
  && listener.remoteEventName === remoteEventName
88
88
  && listener.localEventNamePrefix === localEventNamePrefix);
89
89
  if (!listener) {
90
- listener = {
90
+ const createListenerFn = () => {
91
+ if (remoteEventName === "*") {
92
+ return (eventName, args) => {
93
+ let computedName;
94
+ if (localEventName) {
95
+ computedName = localEventName;
96
+ }
97
+ else if (localEventNamePrefix) {
98
+ computedName = `${localEventNamePrefix}${String(eventName)}`;
99
+ }
100
+ else {
101
+ computedName = eventName;
102
+ }
103
+ return _trigger(computedName, args, returnType, resolve);
104
+ };
105
+ }
106
+ return (...args) => {
107
+ let computedName;
108
+ if (localEventName) {
109
+ computedName = localEventName;
110
+ }
111
+ else if (localEventNamePrefix) {
112
+ computedName = `${localEventNamePrefix}${String(remoteEventName)}`;
113
+ }
114
+ else {
115
+ computedName = remoteEventName;
116
+ }
117
+ return _trigger(computedName, args, returnType, resolve);
118
+ };
119
+ };
120
+ const proxyListener = {
91
121
  localEventName,
92
122
  remoteEventName,
93
123
  localEventNamePrefix,
94
124
  returnType,
95
125
  resolve,
96
- listener: remoteEventName === "*"
97
- ? (eventName, args) => {
98
- const name = localEventName
99
- ? localEventName
100
- : localEventNamePrefix
101
- ? `${localEventNamePrefix}${eventName}`
102
- : eventName;
103
- return _trigger(name,
104
- // @ts-expect-error
105
- args, returnType, resolve);
106
- }
107
- : (...args) => {
108
- const name = localEventName
109
- ? localEventName
110
- : localEventNamePrefix
111
- ? `${localEventNamePrefix}${remoteEventName}`
112
- : remoteEventName;
113
- return _trigger(name,
114
- // @ts-expect-error
115
- args, returnType, resolve);
116
- },
126
+ listener: createListenerFn(),
117
127
  };
118
- proxyListeners.push(listener);
128
+ listener = proxyListener;
129
+ proxyListeners.push(proxyListener);
119
130
  }
120
131
  return listener;
121
132
  };
@@ -146,7 +157,6 @@ function createEventBus(eventBusOptions) {
146
157
  const on = (name, handler, options) => {
147
158
  const e = _getOrAddEvent(name);
148
159
  eventSources.forEach((evs) => {
149
- name;
150
160
  if (evs.eventSource.accepts === false
151
161
  || (typeof evs.eventSource.accepts === "function"
152
162
  && !evs.eventSource.accepts(name))) {
@@ -181,7 +191,7 @@ function createEventBus(eventBusOptions) {
181
191
  if (e) {
182
192
  e.removeListener(handler, context, tag);
183
193
  }
184
- if (eventSources.length > 0) {
194
+ if (eventSources.length > 0 && e) {
185
195
  const isEmpty = !e.hasListener();
186
196
  eventSources.forEach((evs) => {
187
197
  const inx = evs.subscribed.indexOf(name);
@@ -256,6 +266,7 @@ function createEventBus(eventBusOptions) {
256
266
  break;
257
267
  default:
258
268
  e.trigger(...args);
269
+ return undefined;
259
270
  }
260
271
  return result;
261
272
  };
@@ -289,78 +300,64 @@ function createEventBus(eventBusOptions) {
289
300
  return _trigger(name, args, null, false);
290
301
  };
291
302
  const first = (name, ...args) => {
292
- const e = _getOrAddEvent(name);
293
303
  return _trigger(name, args, types_1.TriggerReturnType.FIRST, false);
294
304
  };
295
305
  const resolveFirst = (name, ...args) => {
296
- const e = _getOrAddEvent(name);
297
306
  return _trigger(name, args, types_1.TriggerReturnType.FIRST, true);
298
307
  };
299
308
  const all = (name, ...args) => {
300
- const e = _getOrAddEvent(name);
301
309
  return _trigger(name, args, types_1.TriggerReturnType.ALL, false);
302
310
  };
303
311
  const resolveAll = (name, ...args) => {
304
- const e = _getOrAddEvent(name);
305
312
  return _trigger(name, args, types_1.TriggerReturnType.ALL, true);
306
313
  };
307
314
  const last = (name, ...args) => {
308
- const e = _getOrAddEvent(name);
309
315
  return _trigger(name, args, types_1.TriggerReturnType.LAST, false);
310
316
  };
311
317
  const resolveLast = (name, ...args) => {
312
- const e = _getOrAddEvent(name);
313
318
  return _trigger(name, args, types_1.TriggerReturnType.LAST, true);
314
319
  };
315
320
  const merge = (name, ...args) => {
316
- const e = _getOrAddEvent(name);
317
321
  return _trigger(name, args, types_1.TriggerReturnType.MERGE, false);
318
322
  };
319
323
  const resolveMerge = (name, ...args) => {
320
- const e = _getOrAddEvent(name);
321
324
  return _trigger(name, args, types_1.TriggerReturnType.MERGE, true);
322
325
  };
323
326
  const concat = (name, ...args) => {
324
- const e = _getOrAddEvent(name);
325
327
  return _trigger(name, args, types_1.TriggerReturnType.CONCAT, false);
326
328
  };
327
329
  const resolveConcat = (name, ...args) => {
328
- const e = _getOrAddEvent(name);
329
330
  return _trigger(name, args, types_1.TriggerReturnType.CONCAT, true);
330
331
  };
331
332
  const firstNonEmpty = (name, ...args) => {
332
- const e = _getOrAddEvent(name);
333
333
  return _trigger(name, args, types_1.TriggerReturnType.FIRST_NON_EMPTY, false);
334
334
  };
335
335
  const resolveFirstNonEmpty = (name, ...args) => {
336
- const e = _getOrAddEvent(name);
337
336
  return _trigger(name, args, types_1.TriggerReturnType.FIRST_NON_EMPTY, true);
338
337
  };
339
338
  const untilTrue = (name, ...args) => {
340
- const e = _getOrAddEvent(name);
341
339
  return _trigger(name, args, types_1.TriggerReturnType.UNTIL_TRUE, false);
342
340
  };
343
341
  const untilFalse = (name, ...args) => {
344
- const e = _getOrAddEvent(name);
345
342
  return _trigger(name, args, types_1.TriggerReturnType.UNTIL_FALSE, false);
346
343
  };
347
344
  const pipe = (name, ...args) => {
348
- const e = _getOrAddEvent(name);
349
345
  return _trigger(name, args, types_1.TriggerReturnType.PIPE, false);
350
346
  };
351
347
  const resolvePipe = (name, ...args) => {
352
- const e = _getOrAddEvent(name);
353
348
  return _trigger(name, args, types_1.TriggerReturnType.PIPE, true);
354
349
  };
355
350
  const raw = (name, ...args) => {
356
- const e = _getOrAddEvent(name);
357
351
  return _trigger(name, args, types_1.TriggerReturnType.RAW, false);
358
352
  };
359
353
  const withTags = (tags, callback) => {
360
354
  currentTagsFilter = tags;
361
- const result = callback();
362
- currentTagsFilter = null;
363
- return result;
355
+ try {
356
+ return callback();
357
+ }
358
+ finally {
359
+ currentTagsFilter = null;
360
+ }
364
361
  };
365
362
  const reset = () => {
366
363
  if (eventSources.length > 0) {
@@ -376,14 +373,14 @@ function createEventBus(eventBusOptions) {
376
373
  eventSources.length = 0;
377
374
  };
378
375
  const suspendAll = (withQueue = false) => {
379
- for (const name in events) {
380
- events.get(name).suspend(withQueue);
381
- }
376
+ events.forEach((event) => {
377
+ event.suspend(withQueue);
378
+ });
382
379
  };
383
380
  const resumeAll = () => {
384
- for (const name in events) {
385
- events.get(name).resume();
386
- }
381
+ events.forEach((event) => {
382
+ event.resume();
383
+ });
387
384
  };
388
385
  const relay = ({ eventSource, remoteEventName, localEventName, proxyType, localEventNamePrefix, }) => {
389
386
  const { returnType, resolve } = proxyReturnTypeToTriggerReturnType(proxyType || types_1.ProxyType.TRIGGER);
@@ -435,16 +432,16 @@ function createEventBus(eventBusOptions) {
435
432
  : evs.eventSource.name === eventSource.name);
436
433
  if (inx !== -1) {
437
434
  const evs = eventSources[inx];
438
- evs.subscribed.forEach((name) => {
435
+ evs.subscribed.forEach((subscribedName) => {
439
436
  const { returnType, resolve } = proxyReturnTypeToTriggerReturnType(evs.eventSource.proxyType || types_1.ProxyType.TRIGGER);
440
437
  const listener = _getProxyListener({
441
438
  localEventName: null,
442
- remoteEventName: name,
439
+ remoteEventName: subscribedName,
443
440
  returnType,
444
441
  resolve,
445
442
  localEventNamePrefix: null,
446
443
  });
447
- evs.eventSource.un(name, listener.listener, evs.eventSource);
444
+ evs.eventSource.un(subscribedName, listener.listener, evs.eventSource);
448
445
  });
449
446
  eventSources.splice(inx, 1);
450
447
  }
@@ -4,13 +4,12 @@ exports.default = asyncCall;
4
4
  function asyncCall(fn, context, args, timeout) {
5
5
  return new Promise((resolve, reject) => {
6
6
  const newArgs = [...(args || [])];
7
- // const newArgs = [ ...(args || []) ];
8
7
  setTimeout(() => {
9
8
  try {
10
9
  resolve(fn.apply(context, newArgs));
11
10
  }
12
11
  catch (err) {
13
- reject(err);
12
+ reject(err instanceof Error ? err : new Error(String(err)));
14
13
  }
15
14
  }, timeout || 0);
16
15
  });
@@ -9,6 +9,9 @@ function ErrorBoundary({ children, listener }) {
9
9
  const boundaryErrorListener = (0, react_1.useContext)(exports.ErrorBoundaryContext);
10
10
  const thisRef = (0, react_1.useRef)(listener);
11
11
  const outerRef = (0, react_1.useRef)(boundaryErrorListener);
12
+ // Keep refs in sync with props
13
+ thisRef.current = listener;
14
+ outerRef.current = boundaryErrorListener;
12
15
  const thisErrorListener = (0, react_1.useCallback)((errorResponse) => {
13
16
  if (thisRef.current) {
14
17
  thisRef.current(errorResponse);
@@ -9,12 +9,9 @@ function useListenToActionBus(actionBus, actionName, listener, options, errorLis
9
9
  beforeActionListener = listener.beforeActionListener;
10
10
  listener = listener.listener;
11
11
  }
12
- const actionBusRef = (0, react_1.useRef)(actionBus);
13
12
  const listenerRef = (0, react_1.useRef)(listener || null);
14
- const errorListenerRef = (0, react_1.useRef)(null);
15
13
  const beforeActionListenerRef = (0, react_1.useRef)(null);
16
14
  listenerRef.current = listener || null;
17
- errorListenerRef.current = errorListener || null;
18
15
  beforeActionListenerRef.current = beforeActionListener || null;
19
16
  const genericHandler = (0, react_1.useCallback)((arg) => {
20
17
  var _a;
@@ -24,27 +21,22 @@ function useListenToActionBus(actionBus, actionName, listener, options, errorLis
24
21
  var _a;
25
22
  return ((_a = beforeActionListenerRef.current) === null || _a === void 0 ? void 0 : _a.call(beforeActionListenerRef, ...args)) || undefined;
26
23
  }, []);
27
- const genericErrorListener = (0, react_1.useCallback)((arg) => {
28
- var _a;
29
- return (_a = errorListenerRef.current) === null || _a === void 0 ? void 0 : _a.call(errorListenerRef, arg);
30
- }, []);
24
+ // Main listener + beforeAction listener - tied to actionName
31
25
  (0, react_1.useEffect)(() => {
26
+ actionBus.addListener(actionName, genericHandler, options || undefined);
27
+ actionBus.get(actionName).addBeforeActionListener(genericBeforeActionHandler);
32
28
  return () => {
33
- actionBusRef.current.removeListener(actionName, genericHandler);
34
- actionBusRef.current.get(actionName)
35
- .removeBeforeActionListener(genericBeforeActionHandler);
36
- actionBusRef.current.removeErrorListener(genericErrorListener);
29
+ actionBus.removeListener(actionName, genericHandler);
30
+ actionBus.get(actionName).removeBeforeActionListener(genericBeforeActionHandler);
37
31
  };
38
- }, []);
32
+ }, [actionBus, actionName, genericHandler, genericBeforeActionHandler]);
33
+ // Error listener - bus level
39
34
  (0, react_1.useEffect)(() => {
40
- actionBusRef.current.removeListener(actionName, genericHandler);
41
- actionBusRef.current.get(actionName)
42
- .removeBeforeActionListener(genericBeforeActionHandler);
43
- actionBusRef.current.removeErrorListener(genericErrorListener);
44
- actionBusRef.current = actionBus;
45
- actionBusRef.current.addListener(actionName, genericHandler, options || undefined);
46
- actionBusRef.current.get(actionName)
47
- .addBeforeActionListener(genericBeforeActionHandler);
48
- actionBusRef.current.addErrorListener(genericErrorListener);
49
- }, [actionBus]);
35
+ if (errorListener) {
36
+ actionBus.addErrorListener(errorListener);
37
+ return () => {
38
+ actionBus.removeErrorListener(errorListener);
39
+ };
40
+ }
41
+ }, [actionBus, errorListener]);
50
42
  }
@@ -4,31 +4,22 @@ exports.useListenToEvent = useListenToEvent;
4
4
  const react_1 = require("react");
5
5
  function useListenToEvent(event, listener, options, errorListener) {
6
6
  const listenerRef = (0, react_1.useRef)(listener);
7
- const eventRef = (0, react_1.useRef)(event);
8
- const errorListenerRef = (0, react_1.useRef)(errorListener);
9
7
  listenerRef.current = listener;
10
8
  const genericHandler = (0, react_1.useCallback)((...args) => {
11
9
  return listenerRef.current(...args);
12
10
  }, []);
13
11
  (0, react_1.useEffect)(() => {
12
+ event.addListener(genericHandler, options);
14
13
  return () => {
15
- eventRef.current.removeListener(genericHandler);
14
+ event.removeListener(genericHandler);
16
15
  };
17
- }, []);
18
- (0, react_1.useEffect)(() => {
19
- eventRef.current.removeListener(genericHandler);
20
- eventRef.current = event;
21
- eventRef.current.addListener(genericHandler, options);
22
- }, [event]);
16
+ }, [event, genericHandler]);
23
17
  (0, react_1.useEffect)(() => {
24
- if (errorListenerRef.current !== errorListener) {
25
- if (errorListenerRef.current) {
26
- eventRef.current.removeErrorListener(errorListenerRef.current);
27
- }
28
- errorListenerRef.current = errorListener;
29
- if (errorListener) {
30
- eventRef.current.addErrorListener(errorListener);
31
- }
18
+ if (errorListener) {
19
+ event.addErrorListener(errorListener);
20
+ return () => {
21
+ event.removeErrorListener(errorListener);
22
+ };
32
23
  }
33
- }, [errorListener]);
24
+ }, [event, errorListener]);
34
25
  }
@@ -4,35 +4,25 @@ exports.useListenToEventBus = useListenToEventBus;
4
4
  const react_1 = require("react");
5
5
  function useListenToEventBus(eventBus, eventName, listener, options, errorListener) {
6
6
  const listenerRef = (0, react_1.useRef)(listener);
7
- const eventBusRef = (0, react_1.useRef)(eventBus);
8
- const errorListenerRef = (0, react_1.useRef)(errorListener);
9
7
  listenerRef.current = listener;
10
8
  const genericHandler = (0, react_1.useCallback)((...args) => {
11
9
  var _a;
12
10
  return (_a = listenerRef.current) === null || _a === void 0 ? void 0 : _a.call(listenerRef, ...args);
13
11
  }, []);
12
+ // Main listener - cleanup pattern handles eventBus/eventName changes
14
13
  (0, react_1.useEffect)(() => {
14
+ eventBus.addListener(eventName, genericHandler, options);
15
15
  return () => {
16
- eventBusRef.current.removeListener(eventName, genericHandler);
17
- if (errorListenerRef.current) {
18
- eventBusRef.current.removeErrorListener(errorListenerRef.current);
19
- }
16
+ eventBus.removeListener(eventName, genericHandler);
20
17
  };
21
- }, []);
22
- (0, react_1.useEffect)(() => {
23
- eventBusRef.current.removeListener(eventName, genericHandler);
24
- eventBusRef.current = eventBus;
25
- eventBusRef.current.addListener(eventName, genericHandler, options);
26
- }, [eventBus]);
18
+ }, [eventBus, eventName, genericHandler]);
19
+ // Error listener - cleanup pattern
27
20
  (0, react_1.useEffect)(() => {
28
- if (errorListenerRef.current !== errorListener) {
29
- if (errorListenerRef.current) {
30
- eventBusRef.current.removeErrorListener(errorListenerRef.current);
31
- }
32
- errorListenerRef.current = errorListener;
33
- if (errorListener) {
34
- eventBusRef.current.addErrorListener(errorListener);
35
- }
21
+ if (errorListener) {
22
+ eventBus.addErrorListener(errorListener);
23
+ return () => {
24
+ eventBus.removeErrorListener(errorListener);
25
+ };
36
26
  }
37
- }, [errorListener]);
27
+ }, [eventBus, errorListener]);
38
28
  }
@@ -4,19 +4,14 @@ exports.useListenToStoreChanges = useListenToStoreChanges;
4
4
  const react_1 = require("react");
5
5
  function useListenToStoreChanges(store, key, listener, options) {
6
6
  const listenerRef = (0, react_1.useRef)(listener);
7
- const storeRef = (0, react_1.useRef)(store);
8
7
  listenerRef.current = listener;
9
8
  const genericHandler = (0, react_1.useCallback)((value, previousValue) => {
10
9
  return listenerRef.current(value, previousValue);
11
10
  }, []);
12
11
  (0, react_1.useEffect)(() => {
12
+ store.onChange(key, genericHandler, options);
13
13
  return () => {
14
- storeRef.current.removeOnChange(key, genericHandler);
14
+ store.removeOnChange(key, genericHandler);
15
15
  };
16
- }, []);
17
- (0, react_1.useEffect)(() => {
18
- storeRef.current.removeOnChange(key, genericHandler);
19
- storeRef.current = store;
20
- storeRef.current.onChange(key, genericHandler, options);
21
- }, [store]);
16
+ }, [store, key, genericHandler]);
22
17
  }
@@ -13,15 +13,14 @@ function useStore(initialData = {}, config) {
13
13
  }
14
14
  if (config === null || config === void 0 ? void 0 : config.pipes) {
15
15
  for (const key in config.pipes) {
16
- // @ts-expect-error
16
+ // @ts-expect-error - TS widens for-in key to string; types are correct
17
17
  store.pipe(key, config.pipes[key]);
18
18
  }
19
19
  }
20
20
  if (config === null || config === void 0 ? void 0 : config.control) {
21
21
  for (const key in config.control) {
22
- store.control(
23
- // @ts-expect-error
24
- key, config.control[key]);
22
+ // @ts-expect-error - TS widens for-in key to string; types are correct
23
+ store.control(key, config.control[key]);
25
24
  }
26
25
  }
27
26
  return store;
@@ -1,3 +1,3 @@
1
1
  import { KeyOf } from "../lib/types";
2
2
  import { BaseStore } from "../store";
3
- export declare function useStoreState<TStore extends BaseStore, TKey extends KeyOf<TStore["__type"]["propTypes"]>>(store: TStore, key: TKey): readonly [TStore["__type"]["propTypes"][TKey], (value: TStore["__type"]["propTypes"][TKey] | ((previousValue?: TStore["__type"]["propTypes"][TKey] | undefined) => TStore["__type"]["propTypes"][TKey])) => void];
3
+ export declare function useStoreState<TStore extends BaseStore, TKey extends KeyOf<TStore["__type"]["propTypes"]>>(store: TStore, key: TKey): readonly [TStore["__type"]["propTypes"][TKey], (value: TStore["__type"]["propTypes"][TKey] | ((previousValue?: TStore["__type"]["propTypes"][TKey]) => TStore["__type"]["propTypes"][TKey])) => void];
@@ -27,6 +27,7 @@ function useStoreState(store, key) {
27
27
  storeRef.current = store;
28
28
  keyRef.current = key;
29
29
  storeRef.current.onChange(keyRef.current, onChange);
30
+ setValue(store.get(key));
30
31
  }, [store, key]);
31
32
  return [value, setter];
32
33
  }
package/dist/store.js CHANGED
@@ -69,6 +69,7 @@ function createStore(initialData = {}) {
69
69
  name,
70
70
  });
71
71
  if ((_b = control.get(exports.ErrorEventName)) === null || _b === void 0 ? void 0 : _b.hasListener()) {
72
+ effectKeys = [];
72
73
  return true;
73
74
  }
74
75
  throw error;
@@ -94,6 +95,7 @@ function createStore(initialData = {}) {
94
95
  name,
95
96
  });
96
97
  if ((_d = control.get(exports.ErrorEventName)) === null || _d === void 0 ? void 0 : _d.hasListener()) {
98
+ effectKeys = [];
97
99
  return true;
98
100
  }
99
101
  throw error;
@@ -116,6 +118,7 @@ function createStore(initialData = {}) {
116
118
  name,
117
119
  });
118
120
  if ((_e = control.get(exports.ErrorEventName)) === null || _e === void 0 ? void 0 : _e.hasListener()) {
121
+ effectKeys = [];
119
122
  return true;
120
123
  }
121
124
  throw error;
@@ -171,7 +174,7 @@ function createStore(initialData = {}) {
171
174
  type: "store-control",
172
175
  });
173
176
  if ((_b = control.get(exports.ErrorEventName)) === null || _b === void 0 ? void 0 : _b.hasListener()) {
174
- return true;
177
+ return;
175
178
  }
176
179
  throw error;
177
180
  }
@@ -182,14 +185,16 @@ function createStore(initialData = {}) {
182
185
  }
183
186
  const get = (key) => {
184
187
  if (typeof key === "string") {
185
- return data.get(key);
188
+ const value = data.get(key);
189
+ return value;
186
190
  }
187
191
  else if (Array.isArray(key)) {
188
192
  // return object with given keys
189
- return key.reduce((acc, k) => {
190
- acc[k] = data.get(k);
191
- return acc;
192
- }, {});
193
+ const result = {};
194
+ for (const k of key) {
195
+ result[k] = data.get(k);
196
+ }
197
+ return result;
193
198
  }
194
199
  else {
195
200
  throw new Error(`Invalid key: ${String(key)}`);
@@ -204,7 +209,12 @@ function createStore(initialData = {}) {
204
209
  const getData = () => {
205
210
  return Object.fromEntries(data.entries());
206
211
  };
212
+ let batching = false;
207
213
  const batch = (fn) => {
214
+ if (batching) {
215
+ throw new Error("Nested batch() calls are not supported");
216
+ }
217
+ batching = true;
208
218
  const allChangedKeys = [];
209
219
  const log = [];
210
220
  const controlInterceptor = function (name, [changedKeys]) {
@@ -220,9 +230,14 @@ function createStore(initialData = {}) {
220
230
  };
221
231
  changes.intercept(changeInterceptor);
222
232
  control.intercept(controlInterceptor);
223
- fn();
224
- control.stopIntercepting();
225
- changes.stopIntercepting();
233
+ try {
234
+ fn();
235
+ }
236
+ finally {
237
+ control.stopIntercepting();
238
+ changes.stopIntercepting();
239
+ batching = false;
240
+ }
226
241
  for (const [propName, value, prev] of log) {
227
242
  const changeArgs = [
228
243
  value,
package/package.json CHANGED
@@ -1,34 +1,35 @@
1
1
  {
2
2
  "name": "@kuindji/reactive",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "author": "Ivan Kuindzhi",
5
+ "type": "module",
5
6
  "repository": {
6
7
  "type": "git",
7
8
  "url": "git+https://github.com/kuindji/reactive.git"
8
9
  },
9
10
  "main": "dist/index.js",
10
11
  "devDependencies": {
11
- "@happy-dom/global-registrator": "^18.0.1",
12
+ "@happy-dom/global-registrator": "^20.0.11",
12
13
  "@testing-library/dom": "^10.4.1",
13
- "@testing-library/jest-dom": "^6.6.4",
14
+ "@testing-library/jest-dom": "^6.9.1",
14
15
  "@testing-library/react": "^16.3.0",
15
- "@types/bun": "^1.2.19",
16
- "@types/react": "^19.1.9",
17
- "@typescript-eslint/eslint-plugin": "^8.38.0",
18
- "react": "^19.1.1",
19
- "typescript": "^5",
20
- "typescript-eslint": "^8.38.0"
16
+ "@types/bun": "^1.3.3",
17
+ "@types/react": "^19.2.7",
18
+ "@typescript-eslint/eslint-plugin": "^8.48.0",
19
+ "globals": "^16.5.0",
20
+ "react": "^19.2.0",
21
+ "react-dom": "^19.2.0",
22
+ "typescript": "^5.9.3",
23
+ "typescript-eslint": "^8.48.0"
21
24
  },
22
25
  "exports": {
23
26
  ".": {
24
- "import": "./dist/index.js",
25
- "require": "./dist/index.js",
26
- "types": "./dist/index.d.ts"
27
+ "types": "./dist/index.d.ts",
28
+ "import": "./dist/index.js"
27
29
  },
28
30
  "./react": {
29
- "import": "./dist/react.js",
30
- "require": "./dist/react.js",
31
- "types": "./dist/react.d.ts"
31
+ "types": "./dist/react.d.ts",
32
+ "import": "./dist/react.js"
32
33
  }
33
34
  },
34
35
  "bugs": {
@@ -62,9 +63,10 @@
62
63
  "scripts": {
63
64
  "build": "tsc -p ./tsconfig-build.json",
64
65
  "lint": "bun eslint .",
65
- "test": "bun test tests/**/*.spec.ts*"
66
+ "test": "bun test tests/**/*.spec.ts*",
67
+ "test:types": "tsc -p ./tests/types/tsconfig.json",
68
+ "test:all": "bun run test:types && bun run test"
66
69
  },
67
70
  "sideEffects": false,
68
- "type": "commonjs",
69
71
  "types": "dist/index.d.ts"
70
72
  }