@reclaimprotocol/attestor-core
Version:
<div> <div> <img src="https://raw.githubusercontent.com/reclaimprotocol/.github/main/assets/banners/Attestor-Core.png" /> </div> </div>
129 lines • 8.03 kB
JavaScript
"use strict";
/**
* Connection state machine for managing atomic state transitions.
* Prevents race conditions in connection state management.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConnectionStateMachine = exports.ConnectionState = void 0;
var ConnectionState;
(function (ConnectionState) {
ConnectionState["CONNECTING"] = "connecting";
ConnectionState["CONNECTED"] = "connected";
ConnectionState["CLOSING"] = "closing";
ConnectionState["CLOSED"] = "closed";
})(ConnectionState || (exports.ConnectionState = ConnectionState = {}));
class ConnectionStateMachine {
constructor(initialState = ConnectionState.CONNECTING) {
this.listeners = [];
this.transitionLock = null;
this.currentState = initialState;
}
/**
* Get current state.
*/
getState() {
return this.currentState;
}
/**
* Check if the connection is in any of the specified states.
*/
isInState(...states) {
return states.includes(this.currentState);
}
/**
* Register a state change listener.
*/
onStateChange(listener) {
this.listeners.push(listener);
return () => {
const index = this.listeners.indexOf(listener);
if (index >= 0) {
this.listeners.splice(index, 1);
}
};
}
/**
* Attempt to transition from allowed states to a new state.
* @param fromStates Allowed states to transition from
* @param toState Target state
* @param action Optional action to execute during transition
* @returns Promise that resolves to true if transition succeeded
*/
async transition(fromStates, toState, action) {
// Wait for any existing transition to complete
if (this.transitionLock) {
await this.transitionLock.catch(() => {
// Ignore errors from previous transitions
});
}
// Create a new transition lock
let resolve;
let reject;
this.transitionLock = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
try {
const allowedStates = Array.isArray(fromStates) ? fromStates : [fromStates];
// Check if transition is allowed
if (!allowedStates.includes(this.currentState)) {
resolve();
return false;
}
// If already in target state, no need to transition
if (this.currentState === toState) {
resolve();
return true;
}
const oldState = this.currentState;
// Execute action if provided
if (action) {
await action();
}
// Update state
this.currentState = toState;
// Notify listeners
for (const listener of this.listeners) {
try {
listener(oldState, toState);
}
catch (error) {
// Don't let listener errors break the state machine
console.error('Error in state change listener:', error);
}
}
resolve();
return true;
}
catch (error) {
reject(error);
throw error;
}
finally {
// Clear the transition lock
this.transitionLock = null;
}
}
/**
* Force a state change without checking allowed transitions.
* Use with caution - mainly for error recovery.
*/
async forceState(newState) {
if (this.transitionLock) {
await this.transitionLock.catch(() => { });
}
const oldState = this.currentState;
this.currentState = newState;
// Notify listeners
for (const listener of this.listeners) {
try {
listener(oldState, newState);
}
catch (error) {
console.error('Error in state change listener:', error);
}
}
}
}
exports.ConnectionStateMachine = ConnectionStateMachine;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ubmVjdGlvbi1zdGF0ZS1tYWNoaW5lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2Nvbm5lY3Rpb24tc3RhdGUtbWFjaGluZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztHQUdHOzs7QUFFSCxJQUFZLGVBS1g7QUFMRCxXQUFZLGVBQWU7SUFDMUIsNENBQXlCLENBQUE7SUFDekIsMENBQXVCLENBQUE7SUFDdkIsc0NBQW1CLENBQUE7SUFDbkIsb0NBQWlCLENBQUE7QUFDbEIsQ0FBQyxFQUxXLGVBQWUsK0JBQWYsZUFBZSxRQUsxQjtBQUlELE1BQWEsc0JBQXNCO0lBS2xDLFlBQVksZUFBZ0MsZUFBZSxDQUFDLFVBQVU7UUFIOUQsY0FBUyxHQUEwQixFQUFFLENBQUE7UUFDckMsbUJBQWMsR0FBeUIsSUFBSSxDQUFBO1FBR2xELElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFBO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNILFFBQVE7UUFDUCxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUE7SUFDekIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsU0FBUyxDQUFDLEdBQUcsTUFBeUI7UUFDckMsT0FBTyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQTtJQUMxQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxhQUFhLENBQUMsUUFBNkI7UUFDMUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUE7UUFDN0IsT0FBTyxHQUFHLEVBQUU7WUFDWCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQTtZQUM5QyxJQUFJLEtBQUssSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDaEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFBO1lBQ2hDLENBQUM7UUFD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