You're Invited: Meet the Socket team at BSidesSF and RSAC - April 27 - May 1.RSVP
Socket
Sign inDemoInstall
Socket

@vaadin/hilla-react-signals

Package Overview
Dependencies
Maintainers
0
Versions
127
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vaadin/hilla-react-signals - npm Package Compare versions

Comparing version

to
24.6.0-alpha3

2

core.js

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

import { installAutoSignalTracking } from "@preact/signals-react/runtime";
installAutoSignalTracking();
export * from "@preact/signals-react";
//# sourceMappingURL=core.js.map

22

FullStackSignal.d.ts

@@ -5,2 +5,8 @@ import type { ConnectClient, Subscription } from '@vaadin/hilla-frontend';

/**
* A return type for signal operations.
*/
export type Operation = {
result: Promise<void>;
};
/**
* An abstraction of a signal that tracks the number of subscribers, and calls

@@ -71,2 +77,4 @@ * the provided `onSubscribe` and `onUnsubscribe` callbacks for the first

export declare const $setValueQuietly: unique symbol;
export declare const $resolveOperation: unique symbol;
export declare const $createOperation: unique symbol;
/**

@@ -100,2 +108,6 @@ * A signal that holds a shared value. Each change to the value is propagated to

constructor(value: T | undefined, config: ServerConnectionConfig, id?: string);
protected [$createOperation]({ id, promise }: {
id?: string;
promise?: Promise<void>;
}): Operation;
/**

@@ -111,5 +123,13 @@ * Sets the local value of the signal without sending any events to the server

* @param event - The event to update the server with.
* @returns The server response promise.
*/
protected [$update](event: StateEvent): void;
protected [$update](event: StateEvent): Promise<void>;
/**
* Resolves the operation promise associated with the given event id.
*
* @param eventId - The event id.
* @param reason - The reason to reject the promise (if any).
*/
protected [$resolveOperation](eventId: string, reason?: string): void;
/**
* A method with to process the server response. The implementation is

@@ -116,0 +136,0 @@ * specific for each signal type.

@@ -59,2 +59,6 @@ import { nanoid } from "nanoid";

async update(event) {
const onTheFly = !this.#subscription;
if (onTheFly) {
this.connect();
}
await this.config.client.call(ENDPOINT, "update", {

@@ -64,2 +68,5 @@ clientSignalId: this.#id,

});
if (onTheFly) {
this.disconnect();
}
}

@@ -74,2 +81,4 @@ disconnect() {

const $setValueQuietly = Symbol("setValueQuietly");
const $resolveOperation = Symbol("resolveOperation");
const $createOperation = Symbol("createOperation");
class FullStackSignal extends DependencyTrackingSignal {

@@ -116,2 +125,31 @@ /**

}
// stores the promise handlers associated to operations
#operationPromises = /* @__PURE__ */ new Map();
// creates the obejct to be returned by operations to allow defining callbacks
[$createOperation]({ id, promise }) {
const thens = this.#operationPromises;
const promises = [];
if (promise) {
promises.push(promise);
}
if (id) {
promises.push(
new Promise((resolve, reject) => {
thens.set(id, { resolve, reject });
})
);
}
if (promises.length === 0) {
promises.push(Promise.resolve());
}
return {
result: Promise.allSettled(promises).then((results) => {
const lastResult = results[results.length - 1];
if (lastResult.status === "fulfilled") {
return void 0;
}
throw lastResult.reason;
})
};
}
/**

@@ -131,5 +169,6 @@ * Sets the local value of the signal without sending any events to the server

* @param event - The event to update the server with.
* @returns The server response promise.
*/
[$update](event) {
this.server.update(event).catch((error) => {
async [$update](event) {
return this.server.update(event).catch((error) => {
this.#error.value = error instanceof Error ? error : new Error(String(error));

@@ -140,2 +179,19 @@ }).finally(() => {

}
/**
* Resolves the operation promise associated with the given event id.
*
* @param eventId - The event id.
* @param reason - The reason to reject the promise (if any).
*/
[$resolveOperation](eventId, reason) {
const operationPromise = this.#operationPromises.get(eventId);
if (operationPromise) {
this.#operationPromises.delete(eventId);
if (reason) {
operationPromise.reject(reason);
} else {
operationPromise.resolve();
}
}
}
#connect() {

@@ -156,3 +212,5 @@ this.server.connect().onSubscriptionLost(() => "resubscribe").onNext((event) => {

export {
$createOperation,
$processServerResponse,
$resolveOperation,
$setValueQuietly,

@@ -159,0 +217,0 @@ $update,

import { CollectionSignal } from './CollectionSignal.js';
import { type StateEvent } from './events.js';
import { $processServerResponse, type ServerConnectionConfig } from './FullStackSignal.js';
import { $processServerResponse, type Operation, type ServerConnectionConfig } from './FullStackSignal.js';
import { ValueSignal } from './ValueSignal.js';

@@ -24,3 +24,3 @@ /**

*/
insertLast(value: T): void;
insertLast(value: T): Operation;
/**

@@ -30,4 +30,4 @@ * Removes the given item from the list.

*/
remove(item: ValueSignal<T>): void;
remove(item: ValueSignal<T>): Operation;
}
//# sourceMappingURL=ListSignal.d.ts.map

@@ -9,3 +9,9 @@ import { CollectionSignal } from "./CollectionSignal.js";

} from "./events.js";
import { $processServerResponse, $setValueQuietly, $update } from "./FullStackSignal.js";
import {
$createOperation,
$processServerResponse,
$resolveOperation,
$setValueQuietly,
$update
} from "./FullStackSignal.js";
import { ValueSignal } from "./ValueSignal.js";

@@ -32,2 +38,3 @@ class ListSignal extends CollectionSignal {

if (!event.accepted) {
this[$resolveOperation](event.id, "server rejected the operation");
return;

@@ -42,2 +49,3 @@ }

}
this[$resolveOperation](event.id);
}

@@ -117,3 +125,4 @@ #handleInsertLastUpdate(event) {

const event = createInsertLastStateEvent(value);
this[$update](event);
const promise = this[$update](event);
return this[$createOperation]({ id: event.id, promise });
}

@@ -127,6 +136,7 @@ /**

if (entryToRemove === void 0) {
return;
return { result: Promise.resolve() };
}
const removeEvent = createRemoveStateEvent(entryToRemove.value.id);
this[$update](removeEvent);
const promise = this[$update](removeEvent);
return this[$createOperation]({ id: removeEvent.id, promise });
}

@@ -133,0 +143,0 @@ }

import { type StateEvent } from './events.js';
import { $processServerResponse } from './FullStackSignal.js';
import { $processServerResponse, type Operation } from './FullStackSignal.js';
import { ValueSignal } from './ValueSignal.js';

@@ -40,6 +40,7 @@ /**

* negative.
* @returns An operation object that allows to perform additional actions.
*/
incrementBy(delta: number): void;
incrementBy(delta: number): Operation;
protected [$processServerResponse](event: StateEvent): void;
}
//# sourceMappingURL=NumberSignal.d.ts.map
import { createIncrementStateEvent, isIncrementStateEvent } from "./events.js";
import { $processServerResponse, $setValueQuietly, $update } from "./FullStackSignal.js";
import {
$createOperation,
$processServerResponse,
$resolveOperation,
$setValueQuietly,
$update
} from "./FullStackSignal.js";
import { ValueSignal } from "./ValueSignal.js";

@@ -17,6 +23,7 @@ class NumberSignal extends ValueSignal {

* negative.
* @returns An operation object that allows to perform additional actions.
*/
incrementBy(delta) {
if (delta === 0) {
return;
return { result: Promise.resolve() };
}

@@ -26,11 +33,14 @@ this[$setValueQuietly](this.value + delta);

this.#sentIncrementEvents.set(event.id, event);
this[$update](event);
const promise = this[$update](event);
return this[$createOperation]({ id: event.id, promise });
}
[$processServerResponse](event) {
if (event.accepted && isIncrementStateEvent(event)) {
if (this.#sentIncrementEvents.has(event.id)) {
const sentEvent = this.#sentIncrementEvents.get(event.id);
if (sentEvent) {
this.#sentIncrementEvents.delete(event.id);
return;
} else {
this[$setValueQuietly](this.value + event.value);
}
this[$setValueQuietly](this.value + event.value);
this[$resolveOperation](event.id);
} else {

@@ -37,0 +47,0 @@ super[$processServerResponse](event);

{
"name": "@vaadin/hilla-react-signals",
"version": "24.6.0-alpha2",
"version": "24.6.0-alpha3",
"description": "Signals for Hilla React",

@@ -50,3 +50,3 @@ "main": "index.js",

"@preact/signals-react": "^2.0.0",
"@vaadin/hilla-frontend": "24.6.0-alpha2",
"@vaadin/hilla-frontend": "24.6.0-alpha3",
"nanoid": "^5.0.7"

@@ -53,0 +53,0 @@ },

import { type StateEvent } from './events.js';
import { $processServerResponse, FullStackSignal } from './FullStackSignal.js';
import { $processServerResponse, FullStackSignal, type Operation } from './FullStackSignal.js';
/**
* An operation subscription that can be canceled.
*/
export interface OperationSubscription {
export interface OperationSubscription extends Operation {
cancel(): void;

@@ -31,4 +31,5 @@ }

* @param newValue - The new value.
* @returns An operation object that allows to perform additional actions.
*/
replace(expected: T, newValue: T): void;
replace(expected: T, newValue: T): Operation;
/**

@@ -45,3 +46,3 @@ * Tries to update the value by applying the callback function to the current

* produce the new value.
* @returns An operation subscription that can be canceled.
* @returns An operation object that allows to perform additional actions, including cancellation.
*/

@@ -48,0 +49,0 @@ update(callback: (value: T) => T): OperationSubscription;

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

import { nanoid } from "nanoid";
import {

@@ -7,3 +8,9 @@ createReplaceStateEvent,

} from "./events.js";
import { $processServerResponse, $update, FullStackSignal } from "./FullStackSignal.js";
import {
$createOperation,
$processServerResponse,
$resolveOperation,
$update,
FullStackSignal
} from "./FullStackSignal.js";
class ValueSignal extends FullStackSignal {

@@ -30,2 +37,3 @@ #pendingRequests = /* @__PURE__ */ new Map();

* @param newValue - The new value.
* @returns An operation object that allows to perform additional actions.
*/

@@ -35,3 +43,5 @@ replace(expected, newValue) {

const signalId = parentClientSignalId !== void 0 ? this.id : void 0;
this[$update](createReplaceStateEvent(expected, newValue, signalId, parentClientSignalId));
const event = createReplaceStateEvent(expected, newValue, signalId, parentClientSignalId);
const promise = this[$update](event);
return this[$createOperation]({ id: event.id, promise });
}

@@ -49,3 +59,3 @@ /**

* produce the new value.
* @returns An operation subscription that can be canceled.
* @returns An operation object that allows to perform additional actions, including cancellation.
*/

@@ -55,10 +65,9 @@ update(callback) {

const event = createReplaceStateEvent(this.value, newValue);
this[$update](event);
const waiter = Promise.withResolvers();
const pendingRequest = { callback, waiter, canceled: false };
const promise = this[$update](event);
const pendingRequest = { id: nanoid(), callback, canceled: false };
this.#pendingRequests.set(event.id, pendingRequest);
return {
...this[$createOperation]({ id: pendingRequest.id, promise }),
cancel: () => {
pendingRequest.canceled = true;
pendingRequest.waiter.resolve();
}

@@ -71,14 +80,13 @@ };

this.#pendingRequests.delete(event.id);
}
if (!event.accepted && record) {
if (!record.canceled) {
if (!(event.accepted || record.canceled)) {
this.update(record.callback);
}
}
let reason;
if (event.accepted || isSnapshotStateEvent(event)) {
if (record) {
record.waiter.resolve();
}
this.#applyAcceptedEvent(event);
} else {
reason = "server rejected the operation";
}
[record?.id, event.id].filter(Boolean).forEach((id) => this[$resolveOperation](id, reason));
}

@@ -85,0 +93,0 @@ #applyAcceptedEvent(event) {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet