From bdc6958b498ec96a21ab9d714cef8d17260fc03a Mon Sep 17 00:00:00 2001 From: Lentil Hoffman Date: Wed, 25 Jun 2025 13:37:35 -0500 Subject: [PATCH] more progress --- .../dependency/basic-dependencies.test.ts | 4 +-- .../dependency/circular-dependencies.test.ts | 10 +++--- .../edge-cases/edge-cases.test.ts | 8 ++--- .../integration/multiple-plugins.test.ts | 7 ++-- .../lifecycle/plugin-lifecycle.test.ts | 2 +- .../plugins/count-plugin.test.ts | 2 +- .../plugins/discount-plugins.test.ts | 4 +-- .../custom-resolvers/resolver.test.ts | 2 +- .../views/resolvers/state-visibility.test.ts | 6 ++-- .../api/custom-resolver-class.md | 2 +- .../api/resolver-plugin-interface.md | 6 ++-- docs/custom-resolvers/api/types.md | 10 +++--- .../dependencies/dependency-resolution.md | 4 +-- docs/custom-resolvers/dependencies/index.md | 2 +- .../dependencies/type-safety.md | 6 ++-- .../plugins/creating-plugins.md | 4 +-- src/orchestration/base-orchestrator.ts | 8 ++--- .../resolvers/custom-resolvers/plugin.ts | 36 ++++++++++++++++++- .../plugins/concatenation.plugin.ts | 6 ++-- .../plugins/first-write-wins.plugin.ts | 2 +- .../plugins/last-write-wins.plugin.ts | 2 +- .../plugins/majority-vote.plugin.ts | 3 +- .../custom-resolvers/plugins/max.plugin.ts | 8 ++--- .../custom-resolvers/plugins/min.plugin.ts | 13 +++---- .../plugins/running-average.plugin.ts | 2 +- .../resolvers/custom-resolvers/resolver.ts | 2 +- 26 files changed, 97 insertions(+), 64 deletions(-) diff --git a/__tests__/unit/views/resolvers/custom-resolvers/dependency/basic-dependencies.test.ts b/__tests__/unit/views/resolvers/custom-resolvers/dependency/basic-dependencies.test.ts index 0756a10..2fd54d3 100644 --- a/__tests__/unit/views/resolvers/custom-resolvers/dependency/basic-dependencies.test.ts +++ b/__tests__/unit/views/resolvers/custom-resolvers/dependency/basic-dependencies.test.ts @@ -16,7 +16,7 @@ describe('Basic Dependency Resolution', () => { test('should resolve dependencies in correct order', () => { // Define a simple plugin that depends on another - class FirstPlugin implements ResolverPlugin<{ value: string }, string> { + class FirstPlugin extends ResolverPlugin<{ value: string }, string> { readonly dependencies = [] as const; initialize() { @@ -34,7 +34,7 @@ describe('Basic Dependency Resolution', () => { } - class SecondPlugin implements ResolverPlugin<{ value: string }, string> { + class SecondPlugin extends ResolverPlugin<{ value: string }, string> { readonly dependencies = ['first'] as const; initialize() { diff --git a/__tests__/unit/views/resolvers/custom-resolvers/dependency/circular-dependencies.test.ts b/__tests__/unit/views/resolvers/custom-resolvers/dependency/circular-dependencies.test.ts index e364734..9cdd2ab 100644 --- a/__tests__/unit/views/resolvers/custom-resolvers/dependency/circular-dependencies.test.ts +++ b/__tests__/unit/views/resolvers/custom-resolvers/dependency/circular-dependencies.test.ts @@ -16,7 +16,7 @@ describe('Circular Dependency Detection', () => { test('should detect circular dependencies', () => { // PluginA depends on PluginB - class PluginA implements ResolverPlugin<{ value: string }, string> { + class PluginA extends ResolverPlugin<{ value: string }, string> { readonly dependencies = ['b'] as const; initialize() { @@ -34,7 +34,7 @@ describe('Circular Dependency Detection', () => { // PluginB depends on PluginA (circular dependency) - class PluginB implements ResolverPlugin<{ value: string }, string> { + class PluginB extends ResolverPlugin<{ value: string }, string> { readonly dependencies = ['a'] as const; initialize() { @@ -61,21 +61,21 @@ describe('Circular Dependency Detection', () => { }); test('should detect longer circular dependency chains', () => { - class PluginA implements ResolverPlugin<{ value: string }, string> { + class PluginA extends ResolverPlugin<{ value: string }, string> { readonly dependencies = ['c'] as const; initialize() { return { value: '' }; } update() { return { value: '' }; } resolve() { return 'a'; } } - class PluginB implements ResolverPlugin<{ value: string }, string> { + class PluginB extends ResolverPlugin<{ value: string }, string> { readonly dependencies = ['a'] as const; initialize() { return { value: '' }; } update() { return { value: '' }; } resolve() { return 'b'; } } - class PluginC implements ResolverPlugin<{ value: string }, string> { + class PluginC extends ResolverPlugin<{ value: string }, string> { readonly dependencies = ['b'] as const; initialize() { return { value: '' }; } update() { return { value: '' }; } diff --git a/__tests__/unit/views/resolvers/custom-resolvers/edge-cases/edge-cases.test.ts b/__tests__/unit/views/resolvers/custom-resolvers/edge-cases/edge-cases.test.ts index 0b44b76..ff64ae1 100644 --- a/__tests__/unit/views/resolvers/custom-resolvers/edge-cases/edge-cases.test.ts +++ b/__tests__/unit/views/resolvers/custom-resolvers/edge-cases/edge-cases.test.ts @@ -18,7 +18,7 @@ describe('Edge Cases', () => { test('should handle null values', () => { // Create a type-safe plugin that handles null/undefined values - class NullSafeLastWriteWinsPlugin implements ResolverPlugin<{ value: PropertyTypes | null, timestamp: number }, never> { + class NullSafeLastWriteWinsPlugin extends ResolverPlugin<{ value: PropertyTypes | null, timestamp: number }, never> { readonly dependencies = [] as const; initialize() { @@ -64,7 +64,7 @@ describe('Edge Cases', () => { test('should handle concurrent updates with same timestamp', () => { // Custom plugin that handles concurrent updates with the same timestamp - class ConcurrentUpdatePlugin implements ResolverPlugin<{ value: PropertyTypes, timestamp: number }, never> { + class ConcurrentUpdatePlugin extends ResolverPlugin<{ value: PropertyTypes, timestamp: number }, never> { readonly dependencies = [] as const; initialize() { @@ -125,7 +125,7 @@ describe('Edge Cases', () => { test('should handle very large numbers of updates', () => { // Plugin that handles large numbers of updates efficiently - class CounterPlugin implements ResolverPlugin<{ count: number }, never> { + class CounterPlugin extends ResolverPlugin<{ count: number }, never> { readonly dependencies = [] as const; initialize() { @@ -173,7 +173,7 @@ describe('Edge Cases', () => { test('should handle missing properties gracefully', () => { // No deltas added - should handle empty state // Plugin that handles missing properties gracefully - class MissingPropertyPlugin implements ResolverPlugin<{ initialized: boolean }, never> { + class MissingPropertyPlugin extends ResolverPlugin<{ initialized: boolean }, never> { readonly dependencies = [] as const; initialize() { diff --git a/__tests__/unit/views/resolvers/custom-resolvers/integration/multiple-plugins.test.ts b/__tests__/unit/views/resolvers/custom-resolvers/integration/multiple-plugins.test.ts index 1169e05..f86f0ba 100644 --- a/__tests__/unit/views/resolvers/custom-resolvers/integration/multiple-plugins.test.ts +++ b/__tests__/unit/views/resolvers/custom-resolvers/integration/multiple-plugins.test.ts @@ -11,10 +11,11 @@ import { } from '@src/views/resolvers/custom-resolvers'; // A simple plugin that depends on other plugins -class AveragePlugin implements ResolverPlugin<{ initialized: boolean }, Targets> { +class AveragePlugin extends ResolverPlugin<{ initialized: boolean }, Targets> { readonly dependencies: Targets[] = []; constructor(...targets: Targets[]) { + super(); if (targets.length !== 2) { throw new Error('This AveragePlugin requires exactly two targets'); } @@ -96,8 +97,8 @@ describe('Multiple Plugins Integration', () => { lossless.ingestDelta( createDelta('user1', 'host1') .withTimestamp(1000) - .setProperty('entity1', 'name', 'Test Entity', 'test') - .setProperty('entity1', 'tags', 'tag1', 'test') + .setProperty('entity1', 'name', 'Test Entity', 'test-name') + .setProperty('entity1', 'tags', 'tag1', 'test-tags') .buildV1() ); diff --git a/__tests__/unit/views/resolvers/custom-resolvers/lifecycle/plugin-lifecycle.test.ts b/__tests__/unit/views/resolvers/custom-resolvers/lifecycle/plugin-lifecycle.test.ts index 62569be..7d95cf2 100644 --- a/__tests__/unit/views/resolvers/custom-resolvers/lifecycle/plugin-lifecycle.test.ts +++ b/__tests__/unit/views/resolvers/custom-resolvers/lifecycle/plugin-lifecycle.test.ts @@ -8,7 +8,7 @@ import { import { PropertyTypes } from '@src/core/types'; // A simple plugin for testing lifecycle methods -class LifecycleTestPlugin implements ResolverPlugin { +class LifecycleTestPlugin extends ResolverPlugin { readonly dependencies = [] as const; private initialState: LifecycleTestState = { diff --git a/__tests__/unit/views/resolvers/custom-resolvers/plugins/count-plugin.test.ts b/__tests__/unit/views/resolvers/custom-resolvers/plugins/count-plugin.test.ts index d985351..5b78ee1 100644 --- a/__tests__/unit/views/resolvers/custom-resolvers/plugins/count-plugin.test.ts +++ b/__tests__/unit/views/resolvers/custom-resolvers/plugins/count-plugin.test.ts @@ -4,7 +4,7 @@ import { PropertyTypes } from '@src/core/types'; import type { CollapsedDelta } from '@src/views/lossless'; import { testResolverWithPlugins, createTestDelta } from '@test-helpers/resolver-test-helper'; -class CountPlugin implements ResolverPlugin<{ count: number }, never> { +class CountPlugin extends ResolverPlugin<{ count: number }, never> { readonly dependencies = [] as const; initialize() { diff --git a/__tests__/unit/views/resolvers/custom-resolvers/plugins/discount-plugins.test.ts b/__tests__/unit/views/resolvers/custom-resolvers/plugins/discount-plugins.test.ts index 5642a74..9955583 100644 --- a/__tests__/unit/views/resolvers/custom-resolvers/plugins/discount-plugins.test.ts +++ b/__tests__/unit/views/resolvers/custom-resolvers/plugins/discount-plugins.test.ts @@ -5,7 +5,7 @@ import { testResolverWithPlugins, createTestDelta } from '@test-helpers/resolver import Debug from 'debug'; const debug = Debug('rz:test:discount-plugins'); // Mock plugins for testing -class DiscountPlugin implements ResolverPlugin { +class DiscountPlugin extends ResolverPlugin { readonly name = 'discount' as const; readonly dependencies = [] as const; @@ -28,7 +28,7 @@ class DiscountPlugin implements ResolverPlugin { } } -class DiscountedPricePlugin implements ResolverPlugin { +class DiscountedPricePlugin extends ResolverPlugin { readonly name = 'price' as const; readonly dependencies = ['discount'] as const; diff --git a/__tests__/unit/views/resolvers/custom-resolvers/resolver.test.ts b/__tests__/unit/views/resolvers/custom-resolvers/resolver.test.ts index 1ae16bf..b15268a 100644 --- a/__tests__/unit/views/resolvers/custom-resolvers/resolver.test.ts +++ b/__tests__/unit/views/resolvers/custom-resolvers/resolver.test.ts @@ -8,7 +8,7 @@ import { ResolverPlugin } from '@src/views/resolvers/custom-resolvers/plugin'; // const debug = Debug('rz:test:resolver'); // Mock plugins for testing -class TestPlugin implements ResolverPlugin { +class TestPlugin extends ResolverPlugin { name: string; dependencies: readonly string[]; diff --git a/__tests__/unit/views/resolvers/state-visibility.test.ts b/__tests__/unit/views/resolvers/state-visibility.test.ts index f507fc6..01953be 100644 --- a/__tests__/unit/views/resolvers/state-visibility.test.ts +++ b/__tests__/unit/views/resolvers/state-visibility.test.ts @@ -18,7 +18,7 @@ describe('State Visibility', () => { }); // A test plugin that records which states it sees - class StateSpyPlugin implements ResolverPlugin<{ values: string[] }, 'dependsOn'> { + class StateSpyPlugin extends ResolverPlugin<{ values: string[] }, 'dependsOn'> { readonly dependencies = [] as const; seenStates: Record[] = []; @@ -51,7 +51,7 @@ describe('State Visibility', () => { } // A simple plugin that depends on another property - class DependentPlugin implements ResolverPlugin<{ value: string }, 'dependsOn'> { + class DependentPlugin extends ResolverPlugin<{ value: string }, 'dependsOn'> { readonly dependencies = ['dependsOn'] as const; seenStates: Record[] = []; @@ -189,7 +189,7 @@ describe('State Visibility', () => { }); test('should throw error for unknown dependencies', () => { - class PluginWithBadDeps implements ResolverPlugin<{ value: string }, 'nonexistent'> { + class PluginWithBadDeps extends ResolverPlugin<{ value: string }, 'nonexistent'> { readonly dependencies = ['nonexistent'] as const; initialize() { diff --git a/docs/custom-resolvers/api/custom-resolver-class.md b/docs/custom-resolvers/api/custom-resolver-class.md index 47e3cb6..86846b3 100644 --- a/docs/custom-resolvers/api/custom-resolver-class.md +++ b/docs/custom-resolvers/api/custom-resolver-class.md @@ -164,7 +164,7 @@ const resolver = new CustomResolver(view, { taxRate: new LastWriteWinsPlugin(), // Complex plugin with multiple dependencies - subtotal: new class implements ResolverPlugin { + subtotal: new class extends ResolverPlugin { readonly dependencies = ['unitPrice', 'quantity'] as const; initialize() { return { value: 0 }; } diff --git a/docs/custom-resolvers/api/resolver-plugin-interface.md b/docs/custom-resolvers/api/resolver-plugin-interface.md index d98397a..8b9e3db 100644 --- a/docs/custom-resolvers/api/resolver-plugin-interface.md +++ b/docs/custom-resolvers/api/resolver-plugin-interface.md @@ -93,7 +93,7 @@ Resolves the final value from the current state. ## Example Implementation ```typescript -class CounterPlugin implements ResolverPlugin { +class CounterPlugin extends ResolverPlugin { initialize(): CounterState { return { count: 0 }; @@ -126,7 +126,7 @@ class CounterPlugin implements ResolverPlugin { ### Accessing Dependencies ```typescript -class PriceCalculator implements ResolverPlugin { +class PriceCalculator extends ResolverPlugin { readonly dependencies = ['basePrice', 'taxRate'] as const; update( @@ -147,7 +147,7 @@ class PriceCalculator implements ResolverPlugin { +class OptionalDepPlugin extends ResolverPlugin { readonly dependencies = ['required', 'optional?'] as const; update( diff --git a/docs/custom-resolvers/api/types.md b/docs/custom-resolvers/api/types.md index 4031e69..dd7d620 100644 --- a/docs/custom-resolvers/api/types.md +++ b/docs/custom-resolvers/api/types.md @@ -117,7 +117,7 @@ Configuration object mapping property IDs to their resolver plugins. ### `LastWriteWinsPlugin` ```typescript -class LastWriteWinsPlugin implements ResolverPlugin { +class LastWriteWinsPlugin extends ResolverPlugin { // ... } @@ -130,7 +130,7 @@ interface LastWriteWinsState { ### `FirstWriteWinsPlugin` ```typescript -class FirstWriteWinsPlugin implements ResolverPlugin { +class FirstWriteWinsPlugin extends ResolverPlugin { // ... } @@ -148,7 +148,7 @@ interface ConcatenationOptions { sort?: boolean; } -class ConcatenationPlugin implements ResolverPlugin { +class ConcatenationPlugin extends ResolverPlugin { constructor(private options: ConcatenationOptions = {}) { this.options = { @@ -173,7 +173,7 @@ interface MajorityVoteOptions { minVotes?: number; } -class MajorityVotePlugin implements ResolverPlugin { +class MajorityVotePlugin extends ResolverPlugin { constructor(private options: MajorityVoteOptions = {}) { this.options = { @@ -222,7 +222,7 @@ interface CounterState { type CounterDeps = 'incrementBy' | 'resetThreshold'; // Implement plugin with type safety -class CounterPlugin implements ResolverPlugin { +class CounterPlugin extends ResolverPlugin { readonly dependencies = ['incrementBy', 'resetThreshold'] as const; initialize(): CounterState { diff --git a/docs/custom-resolvers/dependencies/dependency-resolution.md b/docs/custom-resolvers/dependencies/dependency-resolution.md index 3e9cafa..6f3387e 100644 --- a/docs/custom-resolvers/dependencies/dependency-resolution.md +++ b/docs/custom-resolvers/dependencies/dependency-resolution.md @@ -50,7 +50,7 @@ const resolver = new CustomResolver(view, { To make a dependency optional, mark it with a `?` suffix: ```typescript -class MyPlugin implements ResolverPlugin { +class MyPlugin extends ResolverPlugin { readonly dependencies = ['required', 'optional?'] as const; // ... @@ -62,7 +62,7 @@ class MyPlugin implements ResolverPlugin { For plugins that need to determine dependencies at runtime, you can implement a custom resolver: ```typescript -class DynamicDepsPlugin implements ResolverPlugin { +class DynamicDepsPlugin extends ResolverPlugin { getDependencies(config: any): string[] { // Determine dependencies based on config diff --git a/docs/custom-resolvers/dependencies/index.md b/docs/custom-resolvers/dependencies/index.md index 3e8c470..9ea1619 100644 --- a/docs/custom-resolvers/dependencies/index.md +++ b/docs/custom-resolvers/dependencies/index.md @@ -21,7 +21,7 @@ The Custom Resolver system provides a powerful dependency management system that ## Example ```typescript -class TotalPricePlugin implements ResolverPlugin { +class TotalPricePlugin extends ResolverPlugin { readonly dependencies = ['price', 'tax'] as const; initialize(): TotalState { diff --git a/docs/custom-resolvers/dependencies/type-safety.md b/docs/custom-resolvers/dependencies/type-safety.md index 3a0822f..7fa31ad 100644 --- a/docs/custom-resolvers/dependencies/type-safety.md +++ b/docs/custom-resolvers/dependencies/type-safety.md @@ -37,7 +37,7 @@ type DependencyStates = { Dependencies are declared as a readonly array of string literals: ```typescript -class MyPlugin implements ResolverPlugin { +class MyPlugin extends ResolverPlugin { readonly dependencies = ['dep1', 'dep2'] as const; // ... implementation @@ -101,7 +101,7 @@ if (typeof deps.price === 'number') { ### Optional Dependencies ```typescript -class MyPlugin implements ResolverPlugin { +class MyPlugin extends ResolverPlugin { readonly dependencies = ['required', 'optional?'] as const; update(_state: MyState, _value: unknown, _delta: CollapsedDelta, deps: any) { @@ -118,7 +118,7 @@ class MyPlugin implements ResolverPlugin { ```typescript type PriceDependencies = 'price1' | 'price2' | 'price3'; -class PriceAggregator implements ResolverPlugin { +class PriceAggregator extends ResolverPlugin { readonly dependencies: readonly PriceDependencies[] = ['price1', 'price2', 'price3'] as const; update(_state: PriceState, _value: unknown, _delta: CollapsedDelta, deps: any) { diff --git a/docs/custom-resolvers/plugins/creating-plugins.md b/docs/custom-resolvers/plugins/creating-plugins.md index d53ed36..f9ce410 100644 --- a/docs/custom-resolvers/plugins/creating-plugins.md +++ b/docs/custom-resolvers/plugins/creating-plugins.md @@ -11,7 +11,7 @@ A minimal plugin must implement the `ResolverPlugin` interface: ```typescript import { ResolverPlugin } from '../resolver'; -class MyPlugin implements ResolverPlugin { +class MyPlugin extends ResolverPlugin { initialize(): MyState { // Return initial state @@ -40,7 +40,7 @@ class MyPlugin implements ResolverPlugin { To depend on other properties, specify the dependency types: ```typescript -class DiscountedPricePlugin implements ResolverPlugin { +class DiscountedPricePlugin extends ResolverPlugin { readonly dependencies = ['basePrice', 'discount'] as const; initialize(): DiscountState { diff --git a/src/orchestration/base-orchestrator.ts b/src/orchestration/base-orchestrator.ts index 5340233..e7696f6 100644 --- a/src/orchestration/base-orchestrator.ts +++ b/src/orchestration/base-orchestrator.ts @@ -28,7 +28,7 @@ export abstract class BaseOrchestrator implements NodeOrchestrator { * Default implementation does nothing - should be overridden by subclasses * that support direct node connections */ - async connectNodes(node1: NodeHandle, node2: NodeHandle): Promise { + async connectNodes(_node1: NodeHandle, _node2: NodeHandle): Promise { // Default implementation does nothing console.warn('connectNodes not implemented for this orchestrator'); } @@ -38,7 +38,7 @@ export abstract class BaseOrchestrator implements NodeOrchestrator { * Default implementation does nothing - should be overridden by subclasses * that support network partitioning */ - async partitionNetwork(partitions: { groups: string[][] }): Promise { + async partitionNetwork(_partitions: { groups: string[][] }): Promise { // Default implementation does nothing console.warn('partitionNetwork not implemented for this orchestrator'); } @@ -49,8 +49,8 @@ export abstract class BaseOrchestrator implements NodeOrchestrator { * that support resource management */ async setResourceLimits( - handle: NodeHandle, - limits: Partial + _handle: NodeHandle, + _limits: Partial ): Promise { // Default implementation does nothing console.warn('setResourceLimits not implemented for this orchestrator'); diff --git a/src/views/resolvers/custom-resolvers/plugin.ts b/src/views/resolvers/custom-resolvers/plugin.ts index 54793e1..1bbcdf1 100644 --- a/src/views/resolvers/custom-resolvers/plugin.ts +++ b/src/views/resolvers/custom-resolvers/plugin.ts @@ -28,6 +28,40 @@ export abstract class ResolverPlugin< */ dependencies?: readonly D[]; + /** + * Convenience wrapper to avoid calling update() when there is no new value + * @param currentState The current state of the plugin + * @param newValue The new value to apply + * @param delta The delta that triggered the update + * @param dependencies The dependencies of the plugin + * @returns The updated state + */ + applyUpdate( + currentState: T, + newValue?: PropertyTypes, + delta?: CollapsedDelta, + dependencies?: DependencyStates + ): T { + if (newValue === undefined) { + switch(this.dependencies?.length) { + case 0: { + // No dependencies, no new value -- nothing to do. + return currentState; + } + case 1: { + // Only one dependency, use it as the new value. + newValue = dependencies![this.dependencies[0]] as PropertyTypes; + break; + } + default: { + // Pass dependencies as is, and leave newValue undefined. + break; + } + } + } + return this.update(currentState, newValue, delta, dependencies); + }; + /** * Initialize the state for a property */ @@ -38,7 +72,7 @@ export abstract class ResolverPlugin< /** * Process a new value for the property */ - abstract update( + protected abstract update( currentState: T, newValue?: PropertyTypes, delta?: CollapsedDelta, diff --git a/src/views/resolvers/custom-resolvers/plugins/concatenation.plugin.ts b/src/views/resolvers/custom-resolvers/plugins/concatenation.plugin.ts index 244e599..f44bcf9 100644 --- a/src/views/resolvers/custom-resolvers/plugins/concatenation.plugin.ts +++ b/src/views/resolvers/custom-resolvers/plugins/concatenation.plugin.ts @@ -13,10 +13,12 @@ type ConcatenationState = { * * Concatenates all string values with a separator */ -export class ConcatenationPlugin implements ResolverPlugin { +export class ConcatenationPlugin extends ResolverPlugin { readonly dependencies = [] as const; - constructor(private separator: string = ' ') {} + constructor(private separator: string = ' ') { + super(); + } initialize(): ConcatenationState { return { values: [] }; diff --git a/src/views/resolvers/custom-resolvers/plugins/first-write-wins.plugin.ts b/src/views/resolvers/custom-resolvers/plugins/first-write-wins.plugin.ts index 7620949..12b2e29 100644 --- a/src/views/resolvers/custom-resolvers/plugins/first-write-wins.plugin.ts +++ b/src/views/resolvers/custom-resolvers/plugins/first-write-wins.plugin.ts @@ -12,7 +12,7 @@ type FirstWriteWinsState = { * * Keeps the first value that was written, ignoring subsequent writes */ -export class FirstWriteWinsPlugin implements ResolverPlugin { +export class FirstWriteWinsPlugin extends ResolverPlugin { readonly dependencies = [] as const; initialize(): FirstWriteWinsState { diff --git a/src/views/resolvers/custom-resolvers/plugins/last-write-wins.plugin.ts b/src/views/resolvers/custom-resolvers/plugins/last-write-wins.plugin.ts index 4e96aca..a3009e6 100644 --- a/src/views/resolvers/custom-resolvers/plugins/last-write-wins.plugin.ts +++ b/src/views/resolvers/custom-resolvers/plugins/last-write-wins.plugin.ts @@ -12,7 +12,7 @@ type LastWriteWinsState = { * * Keeps the most recent value based on the delta's timestamp */ -export class LastWriteWinsPlugin implements ResolverPlugin { +export class LastWriteWinsPlugin extends ResolverPlugin { readonly dependencies = [] as const; initialize(): LastWriteWinsState { diff --git a/src/views/resolvers/custom-resolvers/plugins/majority-vote.plugin.ts b/src/views/resolvers/custom-resolvers/plugins/majority-vote.plugin.ts index dcf6b58..be9896d 100644 --- a/src/views/resolvers/custom-resolvers/plugins/majority-vote.plugin.ts +++ b/src/views/resolvers/custom-resolvers/plugins/majority-vote.plugin.ts @@ -10,7 +10,7 @@ type MajorityVoteState = { * * Returns the value that appears most frequently */ -export class MajorityVotePlugin implements ResolverPlugin { +export class MajorityVotePlugin extends ResolverPlugin { readonly dependencies = [] as const; initialize(): MajorityVoteState { @@ -21,6 +21,7 @@ export class MajorityVotePlugin implements ResolverPlugin implements ResolverPlugin { +export class MaxPlugin extends ResolverPlugin { name = 'max'; readonly dependencies: Target[] = []; constructor(private readonly target?: Target) { + super(); if (target) { this.dependencies = [target]; } @@ -29,11 +30,8 @@ export class MaxPlugin implements ResolverPlugin currentState.max) { return { max: numValue }; } diff --git a/src/views/resolvers/custom-resolvers/plugins/min.plugin.ts b/src/views/resolvers/custom-resolvers/plugins/min.plugin.ts index b8b3b33..0bf8a2b 100644 --- a/src/views/resolvers/custom-resolvers/plugins/min.plugin.ts +++ b/src/views/resolvers/custom-resolvers/plugins/min.plugin.ts @@ -1,6 +1,5 @@ import { PropertyTypes, PropertyID } from "../../../../core/types"; -import { CollapsedDelta } from "../../../lossless"; -import { ResolverPlugin, DependencyStates } from "../plugin"; +import { DependencyStates, ResolverPlugin } from "../plugin"; type MinPluginState = { min?: number; @@ -11,11 +10,12 @@ type MinPluginState = { * * Tracks the minimum numeric value */ -export class MinPlugin implements ResolverPlugin { +export class MinPlugin extends ResolverPlugin { name = 'min'; readonly dependencies: Target[] = []; constructor(private readonly target?: Target) { + super(); if (target) { this.dependencies = [target]; } @@ -27,12 +27,9 @@ export class MinPlugin implements ResolverPlugin { +export class RunningAveragePlugin extends ResolverPlugin { readonly dependencies = [] as const; initialize(): RunningAverageState { diff --git a/src/views/resolvers/custom-resolvers/resolver.ts b/src/views/resolvers/custom-resolvers/resolver.ts index 7a4c46d..1b81b05 100644 --- a/src/views/resolvers/custom-resolvers/resolver.ts +++ b/src/views/resolvers/custom-resolvers/resolver.ts @@ -291,7 +291,7 @@ export class CustomResolver extends Lossy { // Update the plugin state with the new delta const dependencies = this.getDependencyStates(entityState, plugin); - entityState[pluginKey] = plugin.update(pluginState, propertyValue, updateDelta, dependencies); + entityState[pluginKey] = plugin.applyUpdate(pluginState, propertyValue, updateDelta, dependencies); debugState(`Updated entity state for ${entityId}:`, JSON.stringify(entityState[pluginKey])); }