@kuindji/reactive
Advanced tools
+1
-1
| import type { ApiType, BaseHandler, ErrorListenerSignature, ErrorResponse } from "./lib/types"; | ||
| export type ActionResponse<Response extends any = any, Args extends any[] = any[]> = { | ||
| export type ActionResponse<Response = any, Args extends unknown[] = unknown[]> = { | ||
| response: Response; | ||
@@ -4,0 +4,0 @@ error: null; |
@@ -10,5 +10,3 @@ "use strict"; | ||
| if (errorListener) { | ||
| errorEvent.addListener(({ error, args }) => { | ||
| errorEvent.emit({ error, args, type: "action" }); | ||
| }); | ||
| errorEvent.addListener(errorListener); | ||
| } | ||
@@ -32,2 +30,5 @@ const add = (name, action) => { | ||
| const action = get(name); | ||
| if (!action) { | ||
| throw new Error(`Action ${name} not found`); | ||
| } | ||
| return action.invoke(...args); | ||
@@ -34,0 +35,0 @@ }; |
+1
-1
@@ -121,3 +121,3 @@ import type { ApiType, BaseHandler, ErrorListenerSignature } from "./lib/types"; | ||
| readonly isQueued: () => boolean; | ||
| readonly withTags: <T extends (...args: any[]) => any>(tags: string[], callback: T) => ReturnType<T>; | ||
| readonly withTags: <R>(tags: string[], callback: () => R) => R; | ||
| readonly promise: (options?: ListenerOptions) => Promise<Parameters<ListenerSignature>>; | ||
@@ -124,0 +124,0 @@ readonly first: (...args: Parameters<ListenerSignature>) => ReturnType<ListenerSignature> | undefined; |
+43
-16
@@ -10,3 +10,3 @@ "use strict"; | ||
| let listeners = []; | ||
| let errorListeners = []; | ||
| const errorListeners = []; | ||
| let queue = []; | ||
@@ -120,3 +120,3 @@ let suspended = false; | ||
| const addErrorListener = (handler, context) => { | ||
| if (listeners.find((l) => l.handler === handler && l.context === context)) { | ||
| if (errorListeners.find((l) => l.handler === handler && l.context === context)) { | ||
| return; | ||
@@ -157,2 +157,3 @@ } | ||
| listeners.length = 0; | ||
| errorListeners.length = 0; | ||
| queue.length = 0; | ||
@@ -162,2 +163,5 @@ suspended = false; | ||
| triggered = 0; | ||
| lastTrigger = null; | ||
| sortListeners = false; | ||
| cachedPromise = null; | ||
| }; | ||
@@ -181,3 +185,16 @@ const _listenerCall = (listener, args, resolve = null) => { | ||
| if (result instanceof Promise) { | ||
| result.then(resolve); | ||
| void result.then(resolve).catch((error) => { | ||
| for (const errorListener of errorListeners) { | ||
| errorListener.handler({ | ||
| error: error instanceof Error | ||
| ? error | ||
| : new Error(error), | ||
| args: args, | ||
| type: "event", | ||
| }); | ||
| } | ||
| if (errorListeners.length === 0) { | ||
| throw error; | ||
| } | ||
| }); | ||
| } | ||
@@ -295,3 +312,3 @@ else { | ||
| if (isConsequent && results.length > 0) { | ||
| let prev = results[results.length - 1]; | ||
| const prev = results[results.length - 1]; | ||
| if (hasPromises) { | ||
@@ -369,3 +386,3 @@ const prevPromise = prev instanceof Promise | ||
| return hasPromises | ||
| ? Promise.all(results).then((results) => results.flat()) | ||
| ? Promise.all(results).then((r) => r.flat()) | ||
| : results.flat(); | ||
@@ -375,4 +392,4 @@ } | ||
| return hasPromises | ||
| ? Promise.all(results).then((results) => Object.assign.apply(null, [{}, ...results])) | ||
| : Object.assign.apply(null, [{}, ...results]); | ||
| ? Promise.all(results).then((r) => Object.assign({}, ...r)) | ||
| : Object.assign({}, ...results); | ||
| } | ||
@@ -389,3 +406,5 @@ case types_1.TriggerReturnType.LAST: { | ||
| case types_1.TriggerReturnType.FIRST_NON_EMPTY: { | ||
| return Promise.all(results).then((results) => results.find((r) => r !== undefined && r !== null)); | ||
| return hasPromises | ||
| ? Promise.all(results).then((r) => r.find((item) => item !== undefined && item !== null)) | ||
| : results.find((item) => item !== undefined && item !== null); | ||
| } | ||
@@ -402,12 +421,20 @@ case types_1.TriggerReturnType.PIPE: { | ||
| currentTagsFilter = tags; | ||
| const result = callback(); | ||
| currentTagsFilter = null; | ||
| return result; | ||
| try { | ||
| return callback(); | ||
| } | ||
| finally { | ||
| currentTagsFilter = null; | ||
| } | ||
| }; | ||
| let cachedPromise = null; | ||
| const promise = (options) => { | ||
| return new Promise((resolve) => { | ||
| options = Object.assign(Object.assign({}, (options || {})), { limit: 1 }); | ||
| const l = ((...args) => resolve(args)); | ||
| addListener(l, options); | ||
| }); | ||
| return cachedPromise = cachedPromise | ||
| || new Promise((resolve) => { | ||
| options = Object.assign(Object.assign({}, (options || {})), { limit: 1 }); | ||
| const l = ((...args) => { | ||
| resolve(args); | ||
| cachedPromise = null; | ||
| }); | ||
| addListener(l, options); | ||
| }); | ||
| }; | ||
@@ -414,0 +441,0 @@ const first = (...args) => { |
+21
-21
@@ -69,21 +69,21 @@ import { createEvent } from "./event"; | ||
| readonly add: (name: MapKey, options?: EventOptions<BaseHandler>) => void; | ||
| 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>; | ||
| 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>>; | ||
| 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]>[]>; | ||
| 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]>>[]>>; | ||
| 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]>>[]>>; | ||
| 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>; | ||
| 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>>; | ||
| 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>; | ||
| 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>>; | ||
| 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)[]>; | ||
| 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)[]>>; | ||
| 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>; | ||
| 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>>; | ||
| readonly untilTrue: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => void>; | ||
| readonly untilFalse: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<(...args: Parameters<EventsMap[K]>) => void>; | ||
| 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>; | ||
| 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>>; | ||
| 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)[]>; | ||
| readonly withTags: <T extends (...args: any[]) => any>(tags: string[], callback: T) => ReturnType<T>; | ||
| readonly first: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["first"]>; | ||
| readonly resolveFirst: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveFirst"]>; | ||
| readonly all: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["all"]>; | ||
| readonly resolveAll: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveAll"]>; | ||
| readonly resolve: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveAll"]>; | ||
| readonly last: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["last"]>; | ||
| readonly resolveLast: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveLast"]>; | ||
| readonly merge: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["merge"]>; | ||
| readonly resolveMerge: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveMerge"]>; | ||
| readonly concat: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["concat"]>; | ||
| readonly resolveConcat: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveConcat"]>; | ||
| readonly firstNonEmpty: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["firstNonEmpty"]>; | ||
| readonly resolveFirstNonEmpty: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolveFirstNonEmpty"]>; | ||
| readonly untilTrue: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["untilTrue"]>; | ||
| readonly untilFalse: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["untilFalse"]>; | ||
| readonly pipe: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["pipe"]>; | ||
| readonly resolvePipe: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["resolvePipe"]>; | ||
| readonly raw: <K extends KeyOf<GetEventsMap<EventsMap>>, A extends GetEventsMap<EventsMap>[K]["arguments"]>(name: K, ...args: A) => ReturnType<GetEventTypesMap<EventsMap>[K]["raw"]>; | ||
| readonly withTags: <R>(tags: string[], callback: () => R) => R; | ||
| readonly intercept: (fn: InterceptorFunction) => void; | ||
@@ -98,3 +98,3 @@ readonly stopIntercepting: () => void; | ||
| remoteEventName: MapKey; | ||
| localEventName?: any; | ||
| localEventName?: MapKey | null; | ||
| proxyType?: ProxyType; | ||
@@ -106,3 +106,3 @@ localEventNamePrefix?: string | null; | ||
| remoteEventName: MapKey; | ||
| localEventName?: any; | ||
| localEventName?: MapKey | null; | ||
| proxyType?: ProxyType; | ||
@@ -109,0 +109,0 @@ localEventNamePrefix?: string | null; |
+51
-54
@@ -90,3 +90,33 @@ "use strict"; | ||
| if (!listener) { | ||
| listener = { | ||
| const createListenerFn = () => { | ||
| if (remoteEventName === "*") { | ||
| return (eventName, args) => { | ||
| let computedName; | ||
| if (localEventName) { | ||
| computedName = localEventName; | ||
| } | ||
| else if (localEventNamePrefix) { | ||
| computedName = `${localEventNamePrefix}${String(eventName)}`; | ||
| } | ||
| else { | ||
| computedName = eventName; | ||
| } | ||
| return _trigger(computedName, args, returnType, resolve); | ||
| }; | ||
| } | ||
| return (...args) => { | ||
| let computedName; | ||
| if (localEventName) { | ||
| computedName = localEventName; | ||
| } | ||
| else if (localEventNamePrefix) { | ||
| computedName = `${localEventNamePrefix}${String(remoteEventName)}`; | ||
| } | ||
| else { | ||
| computedName = remoteEventName; | ||
| } | ||
| return _trigger(computedName, args, returnType, resolve); | ||
| }; | ||
| }; | ||
| const proxyListener = { | ||
| localEventName, | ||
@@ -97,25 +127,6 @@ remoteEventName, | ||
| resolve, | ||
| listener: remoteEventName === "*" | ||
| ? (eventName, args) => { | ||
| const name = localEventName | ||
| ? localEventName | ||
| : localEventNamePrefix | ||
| ? `${localEventNamePrefix}${eventName}` | ||
| : eventName; | ||
| return _trigger(name, | ||
| // @ts-expect-error | ||
| args, returnType, resolve); | ||
| } | ||
| : (...args) => { | ||
| const name = localEventName | ||
| ? localEventName | ||
| : localEventNamePrefix | ||
| ? `${localEventNamePrefix}${remoteEventName}` | ||
| : remoteEventName; | ||
| return _trigger(name, | ||
| // @ts-expect-error | ||
| args, returnType, resolve); | ||
| }, | ||
| listener: createListenerFn(), | ||
| }; | ||
| proxyListeners.push(listener); | ||
| listener = proxyListener; | ||
| proxyListeners.push(proxyListener); | ||
| } | ||
@@ -151,3 +162,2 @@ return listener; | ||
| eventSources.forEach((evs) => { | ||
| name; | ||
| if (evs.eventSource.accepts === false | ||
@@ -187,3 +197,3 @@ || (typeof evs.eventSource.accepts === "function" | ||
| } | ||
| if (eventSources.length > 0) { | ||
| if (eventSources.length > 0 && e) { | ||
| const isEmpty = !e.hasListener(); | ||
@@ -263,2 +273,3 @@ eventSources.forEach((evs) => { | ||
| e.trigger(...args); | ||
| return undefined; | ||
| } | ||
@@ -297,67 +308,50 @@ return result; | ||
| const first = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.FIRST, false); | ||
| }; | ||
| const resolveFirst = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.FIRST, true); | ||
| }; | ||
| const all = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.ALL, false); | ||
| }; | ||
| const resolveAll = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.ALL, true); | ||
| }; | ||
| const last = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.LAST, false); | ||
| }; | ||
| const resolveLast = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.LAST, true); | ||
| }; | ||
| const merge = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.MERGE, false); | ||
| }; | ||
| const resolveMerge = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.MERGE, true); | ||
| }; | ||
| const concat = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.CONCAT, false); | ||
| }; | ||
| const resolveConcat = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.CONCAT, true); | ||
| }; | ||
| const firstNonEmpty = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.FIRST_NON_EMPTY, false); | ||
| }; | ||
| const resolveFirstNonEmpty = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.FIRST_NON_EMPTY, true); | ||
| }; | ||
| const untilTrue = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.UNTIL_TRUE, false); | ||
| }; | ||
| const untilFalse = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.UNTIL_FALSE, false); | ||
| }; | ||
| const pipe = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.PIPE, false); | ||
| }; | ||
| const resolvePipe = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.PIPE, true); | ||
| }; | ||
| const raw = (name, ...args) => { | ||
| const e = _getOrAddEvent(name); | ||
| return _trigger(name, args, types_1.TriggerReturnType.RAW, false); | ||
@@ -367,5 +361,8 @@ }; | ||
| currentTagsFilter = tags; | ||
| const result = callback(); | ||
| currentTagsFilter = null; | ||
| return result; | ||
| try { | ||
| return callback(); | ||
| } | ||
| finally { | ||
| currentTagsFilter = null; | ||
| } | ||
| }; | ||
@@ -386,10 +383,10 @@ const reset = () => { | ||
| const suspendAll = (withQueue = false) => { | ||
| for (const name in events) { | ||
| events.get(name).suspend(withQueue); | ||
| } | ||
| events.forEach((event) => { | ||
| event.suspend(withQueue); | ||
| }); | ||
| }; | ||
| const resumeAll = () => { | ||
| for (const name in events) { | ||
| events.get(name).resume(); | ||
| } | ||
| events.forEach((event) => { | ||
| event.resume(); | ||
| }); | ||
| }; | ||
@@ -446,7 +443,7 @@ const relay = ({ eventSource, remoteEventName, localEventName, proxyType, localEventNamePrefix, }) => { | ||
| const evs = eventSources[inx]; | ||
| evs.subscribed.forEach((name) => { | ||
| evs.subscribed.forEach((subscribedName) => { | ||
| const { returnType, resolve } = proxyReturnTypeToTriggerReturnType(evs.eventSource.proxyType || types_1.ProxyType.TRIGGER); | ||
| const listener = _getProxyListener({ | ||
| localEventName: null, | ||
| remoteEventName: name, | ||
| remoteEventName: subscribedName, | ||
| returnType, | ||
@@ -456,3 +453,3 @@ resolve, | ||
| }); | ||
| evs.eventSource.un(name, listener.listener, evs.eventSource); | ||
| evs.eventSource.un(subscribedName, listener.listener, evs.eventSource); | ||
| }); | ||
@@ -459,0 +456,0 @@ eventSources.splice(inx, 1); |
@@ -7,3 +7,2 @@ "use strict"; | ||
| const newArgs = [...(args || [])]; | ||
| // const newArgs = [ ...(args || []) ]; | ||
| setTimeout(() => { | ||
@@ -14,3 +13,3 @@ try { | ||
| catch (err) { | ||
| reject(err); | ||
| reject(err instanceof Error ? err : new Error(String(err))); | ||
| } | ||
@@ -17,0 +16,0 @@ }, timeout || 0); |
@@ -12,2 +12,5 @@ "use strict"; | ||
| const outerRef = (0, react_1.useRef)(boundaryErrorListener); | ||
| // Keep refs in sync with props | ||
| thisRef.current = listener; | ||
| outerRef.current = boundaryErrorListener; | ||
| const thisErrorListener = (0, react_1.useCallback)((errorResponse) => { | ||
@@ -14,0 +17,0 @@ if (thisRef.current) { |
@@ -12,8 +12,5 @@ "use strict"; | ||
| } | ||
| const actionBusRef = (0, react_1.useRef)(actionBus); | ||
| const listenerRef = (0, react_1.useRef)(listener || null); | ||
| const errorListenerRef = (0, react_1.useRef)(null); | ||
| const beforeActionListenerRef = (0, react_1.useRef)(null); | ||
| listenerRef.current = listener || null; | ||
| errorListenerRef.current = errorListener || null; | ||
| beforeActionListenerRef.current = beforeActionListener || null; | ||
@@ -28,25 +25,20 @@ const genericHandler = (0, react_1.useCallback)((arg) => { | ||
| }, []); | ||
| const genericErrorListener = (0, react_1.useCallback)((arg) => { | ||
| var _a; | ||
| return (_a = errorListenerRef.current) === null || _a === void 0 ? void 0 : _a.call(errorListenerRef, arg); | ||
| }, []); | ||
| // Main listener + beforeAction listener - tied to actionName | ||
| (0, react_1.useEffect)(() => { | ||
| actionBus.addListener(actionName, genericHandler, options || undefined); | ||
| actionBus.get(actionName).addBeforeActionListener(genericBeforeActionHandler); | ||
| return () => { | ||
| actionBusRef.current.removeListener(actionName, genericHandler); | ||
| actionBusRef.current.get(actionName) | ||
| .removeBeforeActionListener(genericBeforeActionHandler); | ||
| actionBusRef.current.removeErrorListener(genericErrorListener); | ||
| actionBus.removeListener(actionName, genericHandler); | ||
| actionBus.get(actionName).removeBeforeActionListener(genericBeforeActionHandler); | ||
| }; | ||
| }, []); | ||
| }, [actionBus, actionName, genericHandler, genericBeforeActionHandler]); | ||
| // Error listener - bus level | ||
| (0, react_1.useEffect)(() => { | ||
| actionBusRef.current.removeListener(actionName, genericHandler); | ||
| actionBusRef.current.get(actionName) | ||
| .removeBeforeActionListener(genericBeforeActionHandler); | ||
| actionBusRef.current.removeErrorListener(genericErrorListener); | ||
| actionBusRef.current = actionBus; | ||
| actionBusRef.current.addListener(actionName, genericHandler, options || undefined); | ||
| actionBusRef.current.get(actionName) | ||
| .addBeforeActionListener(genericBeforeActionHandler); | ||
| actionBusRef.current.addErrorListener(genericErrorListener); | ||
| }, [actionBus]); | ||
| if (errorListener) { | ||
| actionBus.addErrorListener(errorListener); | ||
| return () => { | ||
| actionBus.removeErrorListener(errorListener); | ||
| }; | ||
| } | ||
| }, [actionBus, errorListener]); | ||
| } |
@@ -7,4 +7,2 @@ "use strict"; | ||
| const listenerRef = (0, react_1.useRef)(listener); | ||
| const eventRef = (0, react_1.useRef)(event); | ||
| const errorListenerRef = (0, react_1.useRef)(errorListener); | ||
| listenerRef.current = listener; | ||
@@ -15,22 +13,15 @@ const genericHandler = (0, react_1.useCallback)((...args) => { | ||
| (0, react_1.useEffect)(() => { | ||
| event.addListener(genericHandler, options); | ||
| return () => { | ||
| eventRef.current.removeListener(genericHandler); | ||
| event.removeListener(genericHandler); | ||
| }; | ||
| }, []); | ||
| }, [event, genericHandler]); | ||
| (0, react_1.useEffect)(() => { | ||
| eventRef.current.removeListener(genericHandler); | ||
| eventRef.current = event; | ||
| eventRef.current.addListener(genericHandler, options); | ||
| }, [event]); | ||
| (0, react_1.useEffect)(() => { | ||
| if (errorListenerRef.current !== errorListener) { | ||
| if (errorListenerRef.current) { | ||
| eventRef.current.removeErrorListener(errorListenerRef.current); | ||
| } | ||
| errorListenerRef.current = errorListener; | ||
| if (errorListener) { | ||
| eventRef.current.addErrorListener(errorListener); | ||
| } | ||
| if (errorListener) { | ||
| event.addErrorListener(errorListener); | ||
| return () => { | ||
| event.removeErrorListener(errorListener); | ||
| }; | ||
| } | ||
| }, [errorListener]); | ||
| }, [event, errorListener]); | ||
| } |
@@ -7,4 +7,2 @@ "use strict"; | ||
| const listenerRef = (0, react_1.useRef)(listener); | ||
| const eventBusRef = (0, react_1.useRef)(eventBus); | ||
| const errorListenerRef = (0, react_1.useRef)(errorListener); | ||
| listenerRef.current = listener; | ||
@@ -15,26 +13,18 @@ const genericHandler = (0, react_1.useCallback)((...args) => { | ||
| }, []); | ||
| // Main listener - cleanup pattern handles eventBus/eventName changes | ||
| (0, react_1.useEffect)(() => { | ||
| eventBus.addListener(eventName, genericHandler, options); | ||
| return () => { | ||
| eventBusRef.current.removeListener(eventName, genericHandler); | ||
| if (errorListenerRef.current) { | ||
| eventBusRef.current.removeErrorListener(errorListenerRef.current); | ||
| } | ||
| eventBus.removeListener(eventName, genericHandler); | ||
| }; | ||
| }, []); | ||
| }, [eventBus, eventName, genericHandler]); | ||
| // Error listener - cleanup pattern | ||
| (0, react_1.useEffect)(() => { | ||
| eventBusRef.current.removeListener(eventName, genericHandler); | ||
| eventBusRef.current = eventBus; | ||
| eventBusRef.current.addListener(eventName, genericHandler, options); | ||
| }, [eventBus]); | ||
| (0, react_1.useEffect)(() => { | ||
| if (errorListenerRef.current !== errorListener) { | ||
| if (errorListenerRef.current) { | ||
| eventBusRef.current.removeErrorListener(errorListenerRef.current); | ||
| } | ||
| errorListenerRef.current = errorListener; | ||
| if (errorListener) { | ||
| eventBusRef.current.addErrorListener(errorListener); | ||
| } | ||
| if (errorListener) { | ||
| eventBus.addErrorListener(errorListener); | ||
| return () => { | ||
| eventBus.removeErrorListener(errorListener); | ||
| }; | ||
| } | ||
| }, [errorListener]); | ||
| }, [eventBus, errorListener]); | ||
| } |
@@ -7,3 +7,2 @@ "use strict"; | ||
| const listenerRef = (0, react_1.useRef)(listener); | ||
| const storeRef = (0, react_1.useRef)(store); | ||
| listenerRef.current = listener; | ||
@@ -14,11 +13,7 @@ const genericHandler = (0, react_1.useCallback)((value, previousValue) => { | ||
| (0, react_1.useEffect)(() => { | ||
| store.onChange(key, genericHandler, options); | ||
| return () => { | ||
| storeRef.current.removeOnChange(key, genericHandler); | ||
| store.removeOnChange(key, genericHandler); | ||
| }; | ||
| }, []); | ||
| (0, react_1.useEffect)(() => { | ||
| storeRef.current.removeOnChange(key, genericHandler); | ||
| storeRef.current = store; | ||
| storeRef.current.onChange(key, genericHandler, options); | ||
| }, [store]); | ||
| }, [store, key, genericHandler]); | ||
| } |
@@ -16,3 +16,3 @@ "use strict"; | ||
| for (const key in config.pipes) { | ||
| // @ts-expect-error | ||
| // @ts-expect-error - TS widens for-in key to string; types are correct | ||
| store.pipe(key, config.pipes[key]); | ||
@@ -23,5 +23,4 @@ } | ||
| for (const key in config.control) { | ||
| store.control( | ||
| // @ts-expect-error | ||
| key, config.control[key]); | ||
| // @ts-expect-error - TS widens for-in key to string; types are correct | ||
| store.control(key, config.control[key]); | ||
| } | ||
@@ -28,0 +27,0 @@ } |
| import { KeyOf } from "../lib/types"; | ||
| import { BaseStore } from "../store"; | ||
| 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]; | ||
| 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]; |
@@ -30,4 +30,5 @@ "use strict"; | ||
| storeRef.current.onChange(keyRef.current, onChange); | ||
| setValue(store.get(key)); | ||
| }, [store, key]); | ||
| return [value, setter]; | ||
| } |
+24
-9
@@ -72,2 +72,3 @@ "use strict"; | ||
| if ((_b = control.get(exports.ErrorEventName)) === null || _b === void 0 ? void 0 : _b.hasListener()) { | ||
| effectKeys = []; | ||
| return true; | ||
@@ -98,2 +99,3 @@ } | ||
| if ((_d = control.get(exports.ErrorEventName)) === null || _d === void 0 ? void 0 : _d.hasListener()) { | ||
| effectKeys = []; | ||
| return true; | ||
@@ -121,2 +123,3 @@ } | ||
| if ((_e = control.get(exports.ErrorEventName)) === null || _e === void 0 ? void 0 : _e.hasListener()) { | ||
| effectKeys = []; | ||
| return true; | ||
@@ -177,3 +180,3 @@ } | ||
| if ((_b = control.get(exports.ErrorEventName)) === null || _b === void 0 ? void 0 : _b.hasListener()) { | ||
| return true; | ||
| return; | ||
| } | ||
@@ -189,10 +192,12 @@ throw error; | ||
| if (typeof key === "string") { | ||
| return data.get(key); | ||
| const value = data.get(key); | ||
| return value; | ||
| } | ||
| else if (Array.isArray(key)) { | ||
| // return object with given keys | ||
| return key.reduce((acc, k) => { | ||
| acc[k] = data.get(k); | ||
| return acc; | ||
| }, {}); | ||
| const result = {}; | ||
| for (const k of key) { | ||
| result[k] = data.get(k); | ||
| } | ||
| return result; | ||
| } | ||
@@ -212,3 +217,8 @@ else { | ||
| }; | ||
| let batching = false; | ||
| const batch = (fn) => { | ||
| if (batching) { | ||
| throw new Error("Nested batch() calls are not supported"); | ||
| } | ||
| batching = true; | ||
| const allChangedKeys = []; | ||
@@ -229,5 +239,10 @@ const log = []; | ||
| control.intercept(controlInterceptor); | ||
| fn(); | ||
| control.stopIntercepting(); | ||
| changes.stopIntercepting(); | ||
| try { | ||
| fn(); | ||
| } | ||
| finally { | ||
| control.stopIntercepting(); | ||
| changes.stopIntercepting(); | ||
| batching = false; | ||
| } | ||
| for (const [propName, value, prev] of log) { | ||
@@ -234,0 +249,0 @@ const changeArgs = [ |
+19
-17
| { | ||
| "name": "@kuindji/reactive", | ||
| "version": "1.0.21", | ||
| "version": "1.0.23", | ||
| "author": "Ivan Kuindzhi", | ||
| "type": "module", | ||
| "repository": { | ||
@@ -11,23 +12,23 @@ "type": "git", | ||
| "devDependencies": { | ||
| "@happy-dom/global-registrator": "^18.0.1", | ||
| "@happy-dom/global-registrator": "^20.0.11", | ||
| "@testing-library/dom": "^10.4.1", | ||
| "@testing-library/jest-dom": "^6.6.4", | ||
| "@testing-library/jest-dom": "^6.9.1", | ||
| "@testing-library/react": "^16.3.0", | ||
| "@types/bun": "^1.2.19", | ||
| "@types/react": "^19.1.9", | ||
| "@typescript-eslint/eslint-plugin": "^8.38.0", | ||
| "react": "^19.1.1", | ||
| "typescript": "^5", | ||
| "typescript-eslint": "^8.38.0" | ||
| "@types/bun": "^1.3.3", | ||
| "@types/react": "^19.2.7", | ||
| "@typescript-eslint/eslint-plugin": "^8.48.0", | ||
| "globals": "^16.5.0", | ||
| "react": "^19.2.0", | ||
| "react-dom": "^19.2.0", | ||
| "typescript": "^5.9.3", | ||
| "typescript-eslint": "^8.48.0" | ||
| }, | ||
| "exports": { | ||
| ".": { | ||
| "import": "./dist/index.js", | ||
| "require": "./dist/index.js", | ||
| "types": "./dist/index.d.ts" | ||
| "types": "./dist/index.d.ts", | ||
| "import": "./dist/index.js" | ||
| }, | ||
| "./react": { | ||
| "import": "./dist/react.js", | ||
| "require": "./dist/react.js", | ||
| "types": "./dist/react.d.ts" | ||
| "types": "./dist/react.d.ts", | ||
| "import": "./dist/react.js" | ||
| } | ||
@@ -66,7 +67,8 @@ }, | ||
| "lint": "bun eslint .", | ||
| "test": "bun test tests/**/*.spec.ts*" | ||
| "test": "bun test tests/**/*.spec.ts*", | ||
| "test:types": "tsc -p ./tests/types/tsconfig.json", | ||
| "test:all": "bun run test:types && bun run test" | ||
| }, | ||
| "sideEffects": false, | ||
| "type": "commonjs", | ||
| "types": "dist/index.d.ts" | ||
| } |
+9
-10
@@ -120,4 +120,4 @@ # @kuindji/reactive | ||
| }[]; | ||
| } | ||
| const event = createEvent(<() => Partial<ApplicationData>>); | ||
| }; | ||
| const event = createEvent<() => Partial<ApplicationData>>(); | ||
| event.addListener(() => { | ||
@@ -128,5 +128,5 @@ return { | ||
| role: "admin", | ||
| loggedIn: true | ||
| } | ||
| } | ||
| loggedIn: true, | ||
| }, | ||
| }; | ||
| }); | ||
@@ -138,9 +138,8 @@ event.addListener(() => { | ||
| type: "chat", | ||
| message: "You've got a new message!" | ||
| } | ||
| ] | ||
| } | ||
| message: "You've got a new message!", | ||
| }, | ||
| ], | ||
| }; | ||
| }); | ||
| const applicationData = event.merge(); | ||
@@ -147,0 +146,0 @@ ``` |
2874
0.24%Yes
NaN159643
-0.66%12
20%996
-0.1%