🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@kuindji/reactive

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@kuindji/reactive - npm Package Compare versions

Comparing version
1.3.1
to
1.3.2
+5
dist/lib/eventInternal.d.ts
import type { TriggerReturnType } from "./types.js";
export declare const EventTriggerInternal: unique symbol;
export type EventTriggerInternalApi = {
[EventTriggerInternal]: (args: any[], returnType?: TriggerReturnType | null, tags?: string[] | null) => unknown;
};
// Private bridge used by EventBus to observe the result of Event.trigger()
// without changing Event's public fire-and-forget return type.
export const EventTriggerInternal = Symbol("eventTriggerInternal");
+6
-3

@@ -18,3 +18,3 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

const { trigger, addListener, removeAllListeners, removeListener, updateListenerOptions, promise, addErrorListener: addResponseErrorListener, destroy: destroyResponseEvent, } = createEvent();
const { all: triggerBeforeAction, addListener: addBeforeActionListener, removeAllListeners: removeAllBeforeActionListeners, removeListener: removeBeforeActionListener, promise: beforeActionPromise, destroy: destroyBeforeEvent, } = createEvent();
const { raw: triggerBeforeAction, addListener: addBeforeActionListener, removeAllListeners: removeAllBeforeActionListeners, removeListener: removeBeforeActionListener, promise: beforeActionPromise, destroy: destroyBeforeEvent, } = createEvent();
const { trigger: triggerError, addListener: addErrorListener, removeAllListeners: removeAllErrorListeners, removeListener: removeErrorListener, promise: errorPromise, hasListener: hasErrorListeners, destroy: destroyErrorEvent, } = createEvent();

@@ -134,4 +134,7 @@ // Status is a side channel over the invoke lifecycle: a dedicated event so

const beforeResponse = triggerBeforeAction(...args);
const beforeResults = isPromiseLike(beforeResponse)
? yield Promise.resolve(beforeResponse)
// raw() always preserves the array container. Await its entries only
// when needed so synchronous before listeners and the action itself
// retain their existing same-tick execution timing.
const beforeResults = beforeResponse.some(isPromiseLike)
? yield Promise.all(beforeResponse.map((result) => Promise.resolve(result)))
: beforeResponse;

@@ -138,0 +141,0 @@ for (const before of beforeResults) {

import asyncCall from "./lib/asyncCall.js";
import { EventTriggerInternal } from "./lib/eventInternal.js";
import isPromiseLike from "./lib/isPromiseLike.js";

@@ -370,2 +371,19 @@ import listenerSorter from "./lib/listenerSorter.js";

};
const handleListenerError = (error, args) => {
const response = {
error: error instanceof Error ? error : new Error(String(error)),
args,
type: "event",
};
// Snapshot both the listeners and handledness before dispatch. A handler
// may remove itself; that must not skip the next handler or turn an error
// that was handled into an unhandled one after the fact.
const handlers = errorListeners.slice();
if (handlers.length === 0) {
throw error;
}
for (const errorListener of handlers) {
errorListener.handler.call(errorListener.context, response);
}
};
const _listenerCall = (listener, args, resolve = null) => {

@@ -388,14 +406,3 @@ let isAsync = listener.async;

const handledResult = Promise.resolve(result).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;
}
handleListenerError(error, args);
return undefined;

@@ -414,14 +421,3 @@ });

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;
}
handleListenerError(error, args);
return undefined;

@@ -632,10 +628,6 @@ }

case TriggerReturnType.ALL: {
return hasPromises
? Promise.all(results)
: results;
return results;
}
case TriggerReturnType.CONCAT: {
return hasPromises
? Promise.all(results).then((r) => r.flat())
: results.flat();
return results.flat();
}

@@ -706,6 +698,3 @@ case TriggerReturnType.MERGE: {

const response = _trigger(args, TriggerReturnType.ALL);
if (isPromiseLike(response)) {
return Promise.resolve(response);
}
return Promise.resolve(response);
return Promise.all(response.map((item) => Promise.resolve(item)));
};

@@ -737,6 +726,3 @@ const last = (...args) => {

const response = _trigger(args, TriggerReturnType.CONCAT);
if (isPromiseLike(response)) {
return Promise.resolve(response);
}
return Promise.resolve(response);
return Promise.all(response.map((item) => Promise.resolve(item))).then((results) => results.flat());
};

@@ -835,3 +821,6 @@ const firstNonEmpty = (...args) => {

};
Object.defineProperty(api, EventTriggerInternal, {
value: _trigger,
});
return api;
}
import { createEvent } from "./event.js";
import { EventTriggerInternal, } from "./lib/eventInternal.js";
import isPromiseLike from "./lib/isPromiseLike.js";

@@ -85,4 +86,22 @@ import { normalizeEventOptions } from "./lib/normalizeEventOptions.js";

const relays = [];
const errorEvent = createEvent();
const handleError = (name, error, args) => {
// Capture handledness before dispatch: a one-shot or self-removing error
// listener still handled this error even though it is gone afterwards.
const handled = errorEvent.hasListener();
errorEvent.trigger({
name,
error: error instanceof Error ? error : new Error(String(error)),
args,
type: "event",
});
if (handled) {
return undefined;
}
throw error;
};
const asterisk = createEvent();
const errorEvent = createEvent();
const triggerEvent = (event, args) => {
return event[EventTriggerInternal](args);
};
const _getProxyListener = ({ remoteEventName, localEventName, returnType, resolve, localEventNamePrefix, }) => {

@@ -270,16 +289,3 @@ let listener = proxyListeners.find((listener) => listener.returnType === returnType

const e = _getOrAddEvent(name);
const handleError = (error) => {
errorEvent.trigger({
name,
error: error instanceof Error
? error
: new Error(String(error)),
args,
type: "event",
});
if (errorEvent.hasListener()) {
return undefined;
}
throw error;
};
const handleTriggerError = (error) => handleError(name, error, args);
const runner = () => {

@@ -327,4 +333,3 @@ let result;

default:
e.trigger(...args);
return undefined;
return triggerEvent(e, args);
}

@@ -341,5 +346,8 @@ return result;

}
asterisk.trigger(name, args, currentTagsFilter);
const allEventsResult = triggerEvent(asterisk, [name, args, currentTagsFilter]);
if (isPromiseLike(allEventsResult)) {
void Promise.resolve(allEventsResult).catch(handleTriggerError);
}
if (isPromiseLike(result)) {
return Promise.resolve(result).catch(handleError);
return Promise.resolve(result).catch(handleTriggerError);
}

@@ -349,3 +357,3 @@ return result;

catch (error) {
return handleError(error);
return handleTriggerError(error);
}

@@ -352,0 +360,0 @@ };

@@ -1,2 +0,2 @@

import { useContext, useEffect, useMemo, useRef } from "react";
import { useContext, useEffect, useLayoutEffect, useMemo, useRef, } from "react";
import { createAction } from "../action.js";

@@ -31,3 +31,6 @@ import { ErrorBoundaryContext } from "./ErrorBoundary.js";

// initial render).
useEffect(() => {
// Commit the replacement before descendant passive effects can invoke the
// action, while keeping abandoned renders from leaking a new implementation
// into the currently committed action.
useLayoutEffect(() => {
if (actionSignatureRef.current !== actionSignature) {

@@ -34,0 +37,0 @@ action.setAction(actionSignature);

@@ -1,2 +0,2 @@

import { useContext, useEffect, useMemo, useRef } from "react";
import { useContext, useEffect, useLayoutEffect, useMemo, useRef, } from "react";
import { createActionBus } from "../actionBus.js";

@@ -21,17 +21,17 @@ import { ErrorBoundaryContext } from "./ErrorBoundary.js";

const appliedActionsRef = useRef(Object.assign({}, initialActions));
const nextActions = (initialActions !== null && initialActions !== void 0 ? initialActions : {});
// Add newly-introduced actions during render (not in an effect): React runs
// child passive effects BEFORE parent passive effects, so a child rendered
// in the same pass that subscribes to a new action would otherwise throw
// "Action <name> not found". Parent render precedes child render, and
// add() is idempotent (a no-op if the action already exists).
for (const key in nextActions) {
actionBus.add(key, nextActions[key]);
}
// Replacements and removals can be deferred to a passive effect: a replaced
// action keeps its identity/listeners (so subscriptions are unaffected by
// timing), and removing late is harmless.
useEffect(() => {
// Reconcile only after this render commits, so a suspended/abandoned render
// cannot leak actions into the live bus. Layout effects finish before
// descendant passive effects, so newly-added actions are still present
// before children subscribe or invoke them and replacements are never stale.
useLayoutEffect(() => {
const next = (initialActions !== null && initialActions !== void 0 ? initialActions : {});
const prev = appliedActionsRef.current;
for (const key in next) {
if (!(key in prev)) {
actionBus.add(key, next[key]);
}
else if (next[key] !== prev[key]) {
actionBus.replace(key, next[key]);
}
}
for (const key in prev) {

@@ -42,7 +42,2 @@ if (!(key in next)) {

}
for (const key in next) {
if (key in prev && next[key] !== prev[key]) {
actionBus.replace(key, next[key]);
}
}
appliedActionsRef.current = Object.assign({}, next);

@@ -49,0 +44,0 @@ });

@@ -1,2 +0,2 @@

import { useContext, useEffect, useMemo, useRef } from "react";
import { useContext, useLayoutEffect, useMemo, useRef, } from "react";
import { createActionMap } from "../actionMap.js";

@@ -22,3 +22,5 @@ import { ActionMapSetErrorListeners } from "../lib/actionMapInternal.js";

// keeps a defensive throw.
useEffect(() => {
// Reconcile during commit before descendant passive effects can invoke an
// entry, without exposing functions from abandoned renders.
useLayoutEffect(() => {
const next = actions;

@@ -25,0 +27,0 @@ const prev = committedActionsRef.current;

@@ -1,2 +0,2 @@

import { useCallback, useLayoutEffect, useMemo, useRef, useSyncExternalStore, } from "react";
import { useCallback, useInsertionEffect, useMemo, useRef, useSyncExternalStore, } from "react";
import { createAction } from "../action.js";

@@ -28,10 +28,10 @@ /**

// passive effects — which a useEffect+setAction swap would miss, invoking
// the previous fn. The ref is updated in a layout effect (commit phase),
// the previous fn. The ref is updated in an insertion effect (commit phase),
// not during render: a render-phase mutation would leak a fn from a
// suspended or abandoned concurrent render that never commits into the
// currently committed UI. Layout effects run only for committed renders,
// and this one runs before any consumer layout effect declared after the
// hook call, so consumers still observe the latest fn.
// currently committed UI. Insertion effects run only for committed renders
// and finish before descendant layout effects, so every consumer observes
// the latest committed function.
const fnRef = useRef(fn);
useLayoutEffect(() => {
useInsertionEffect(() => {
fnRef.current = fn;

@@ -38,0 +38,0 @@ });

@@ -58,2 +58,11 @@ import { createEventBus } from "./eventBus.js";

};
const reportStoreError = (response) => {
var _a;
// Handledness belongs to the dispatch that is about to happen. A
// self-removing/one-shot error listener must still count as having
// handled this error after it removes itself during the callback.
const handled = !!((_a = control.get(ErrorEventName)) === null || _a === void 0 ? void 0 : _a.hasListener());
control.trigger(ErrorEventName, response);
return handled;
};
const dedupe = (keys) => Array.from(new Set(keys));

@@ -85,3 +94,3 @@ // A public set() can trigger a computed cascade. Routing it through batch()

const _set = (name, value, triggerChange = true, runBeforeChange = true) => {
var _a, _b, _c, _d, _e;
var _a;
const prev = data.get(name);

@@ -106,3 +115,3 @@ if (prev !== value) {

catch (error) {
control.trigger(ErrorEventName, {
const handled = reportStoreError({
error: error instanceof Error

@@ -115,3 +124,3 @@ ? error

});
if ((_a = control.get(ErrorEventName)) === null || _a === void 0 ? void 0 : _a.hasListener()) {
if (handled) {
return false;

@@ -143,3 +152,3 @@ }

catch (error) {
control.trigger(ErrorEventName, {
const handled = reportStoreError({
error: error instanceof Error

@@ -152,3 +161,3 @@ ? error

});
if (!((_b = control.get(ErrorEventName)) === null || _b === void 0 ? void 0 : _b.hasListener())) {
if (!handled) {
deferredChangeError = error;

@@ -158,3 +167,3 @@ hasDeferredChangeError = true;

}
if ((_c = control.get(EffectEventName)) === null || _c === void 0 ? void 0 : _c.hasListener()) {
if ((_a = control.get(EffectEventName)) === null || _a === void 0 ? void 0 : _a.hasListener()) {
try {

@@ -175,3 +184,3 @@ const isIntercepting = control.isIntercepting();

catch (error) {
control.trigger(ErrorEventName, {
const handled = reportStoreError({
error: error instanceof Error

@@ -184,3 +193,3 @@ ? error

});
if ((_d = control.get(ErrorEventName)) === null || _d === void 0 ? void 0 : _d.hasListener()) {
if (handled) {
effectKeys = [];

@@ -204,3 +213,3 @@ return true;

catch (error) {
control.trigger(ErrorEventName, {
const handled = reportStoreError({
error: error instanceof Error

@@ -213,3 +222,3 @@ ? error

});
if ((_e = control.get(ErrorEventName)) === null || _e === void 0 ? void 0 : _e.hasListener()) {
if (handled) {
effectKeys = [];

@@ -273,3 +282,2 @@ return true;

const replayCoalescedLog = (log, hasCallbackError) => {
var _a;
const coalesced = new Map();

@@ -297,3 +305,3 @@ for (const [propName, value, prev] of log) {

catch (error) {
control.trigger(ErrorEventName, {
const handled = reportStoreError({
error: error instanceof Error

@@ -306,3 +314,3 @@ ? error

});
if ((_a = control.get(ErrorEventName)) === null || _a === void 0 ? void 0 : _a.hasListener()) {
if (handled) {
continue;

@@ -362,3 +370,3 @@ }

const applySet = (name, value) => {
var _a, _b;
var _a;
if (typeof name === "string") {

@@ -398,3 +406,2 @@ _set(name, value);

changedKeys.forEach((k) => {
var _a;
// Mirror _set's effect error contract: a throwing effect

@@ -407,3 +414,3 @@ // listener routes to the error event (and is swallowed if

catch (error) {
control.trigger(ErrorEventName, {
const handled = reportStoreError({
error: error instanceof Error

@@ -416,3 +423,3 @@ ? error

});
if (!((_a = control.get(ErrorEventName)) === null || _a === void 0 ? void 0 : _a.hasListener())) {
if (!handled) {
throw error;

@@ -450,3 +457,3 @@ }

if (controlError) {
control.trigger(ErrorEventName, {
const handled = reportStoreError({
error: controlError,

@@ -456,3 +463,3 @@ args: [name],

});
if ((_b = control.get(ErrorEventName)) === null || _b === void 0 ? void 0 : _b.hasListener()) {
if (handled) {
return;

@@ -528,3 +535,2 @@ }

const batch = (fn) => {
var _a;
if (batching) {

@@ -579,3 +585,3 @@ throw new Error("Nested batch() calls are not supported");

catch (error) {
control.trigger(ErrorEventName, {
const handled = reportStoreError({
error: error instanceof Error

@@ -587,3 +593,3 @@ ? error

});
if ((_a = control.get(ErrorEventName)) === null || _a === void 0 ? void 0 : _a.hasListener()) {
if (handled) {
if (hasCallbackError) {

@@ -590,0 +596,0 @@ throw callbackError;

{
"name": "@kuindji/reactive",
"version": "1.3.1",
"version": "1.3.2",
"author": "Ivan Kuindzhi",

@@ -5,0 +5,0 @@ "type": "module",