break up library, move bots to their own repositories

This commit is contained in:
JB
2026-02-12 21:05:15 -05:00
parent 415aa3dbfe
commit cb39431a11
289 changed files with 1931 additions and 6235 deletions

View File

@@ -0,0 +1,73 @@
import cloneDeep from 'lodash/cloneDeep';
/**
* Creates a reactive state object that batches changes and notifies all subscribers with the full old and new state.
*
* @param initialState - The initial state object
* @returns Object with { state: reactive proxy, subscribe: function to add callbacks }
*
* @example
* ```typescript
* const { state, subscribe } = createBatchedReactiveState({ count: 0, user: { name: 'Alice' } });
*
* const unsubscribe1 = subscribe((newState, oldState) => {
* console.log('Subscriber 1:', oldState, '->', newState);
* });
*
* const unsubscribe2 = subscribe((newState, oldState) => {
* console.log('Subscriber 2:', newState.count);
* });
*
* state.count = 1; // Triggers both subscribers once
* state.user.name = 'Bob'; // Triggers both subscribers once (batched)
*
* unsubscribe1(); // Remove first subscriber
* state.count = 2; // Only subscriber 2 is called
* ```
*/
export function createReactiveState<T extends object>(initialState: T) {
const callbacks = new Set<(newState: T, oldState: T) => void>();
let isBatching = false;
let oldState: T | null = null;
let scheduled = false;
const rootState = cloneDeep(initialState);
function createReactiveObject(obj: any): any {
return new Proxy(obj, {
get(target, property, receiver) {
const value = Reflect.get(target, property, receiver);
return typeof value === 'object' && value !== null ? createReactiveObject(value) : value;
},
set(target, property, value, receiver) {
if (!isBatching) {
isBatching = true;
oldState = cloneDeep(rootState);
}
const success = Reflect.set(target, property, value, receiver);
if (success) {
if (!scheduled) {
scheduled = true;
queueMicrotask(() => {
callbacks.forEach((cb) => cb(rootState, oldState!));
isBatching = false;
oldState = null;
scheduled = false;
});
}
}
return success;
},
});
}
const state = createReactiveObject(rootState);
return [
state,
function subscribe(callback: (newState: T, oldState: T) => void) {
callbacks.add(callback);
return () => callbacks.delete(callback);
},
] as const;
}