@proto-kit/common 0.1.1-develop.339 → 0.1.1-develop.455

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/config/ConfigurableModule.d.ts +2 -1
  2. package/dist/config/ConfigurableModule.d.ts.map +1 -1
  3. package/dist/config/ModuleContainer.d.ts +35 -11
  4. package/dist/config/ModuleContainer.d.ts.map +1 -1
  5. package/dist/config/ModuleContainer.js +86 -19
  6. package/dist/dependencyFactory/DependencyFactory.d.ts +13 -9
  7. package/dist/dependencyFactory/DependencyFactory.d.ts.map +1 -1
  8. package/dist/dependencyFactory/DependencyFactory.js +1 -97
  9. package/dist/events/EventEmitter.d.ts +14 -0
  10. package/dist/events/EventEmitter.d.ts.map +1 -0
  11. package/dist/events/EventEmitter.js +35 -0
  12. package/dist/events/EventEmitterProxy.d.ts +17 -0
  13. package/dist/events/EventEmitterProxy.d.ts.map +1 -0
  14. package/dist/events/EventEmitterProxy.js +21 -0
  15. package/dist/events/EventEmittingComponent.d.ts +6 -0
  16. package/dist/events/EventEmittingComponent.d.ts.map +1 -0
  17. package/dist/index.d.ts +7 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +7 -0
  20. package/dist/trees/InMemoryMerkleTreeStorage.d.ts +11 -0
  21. package/dist/trees/InMemoryMerkleTreeStorage.d.ts.map +1 -0
  22. package/dist/trees/InMemoryMerkleTreeStorage.js +12 -0
  23. package/dist/trees/MerkleTreeStore.d.ts +5 -0
  24. package/dist/trees/MerkleTreeStore.d.ts.map +1 -0
  25. package/dist/trees/MerkleTreeStore.js +1 -0
  26. package/dist/trees/MockAsyncMerkleStore.d.ts +9 -0
  27. package/dist/trees/MockAsyncMerkleStore.d.ts.map +1 -0
  28. package/dist/trees/MockAsyncMerkleStore.js +19 -0
  29. package/dist/trees/RollupMerkleTree.d.ts +126 -0
  30. package/dist/trees/RollupMerkleTree.d.ts.map +1 -0
  31. package/dist/trees/RollupMerkleTree.js +216 -0
  32. package/dist/types.d.ts +5 -0
  33. package/dist/types.d.ts.map +1 -1
  34. package/dist/zkProgrammable/ZkProgrammable.d.ts +1 -1
  35. package/dist/zkProgrammable/ZkProgrammable.d.ts.map +1 -1
  36. package/dist/zkProgrammable/ZkProgrammable.js +4 -4
  37. package/dist/zkProgrammable/provableMethod.d.ts +1 -1
  38. package/dist/zkProgrammable/provableMethod.d.ts.map +1 -1
  39. package/dist/zkProgrammable/provableMethod.js +2 -2
  40. package/package.json +2 -2
  41. package/src/config/ConfigurableModule.ts +3 -1
  42. package/src/config/ModuleContainer.ts +150 -30
  43. package/src/dependencyFactory/DependencyFactory.ts +25 -114
  44. package/src/events/EventEmitter.ts +58 -0
  45. package/src/events/EventEmitterProxy.ts +57 -0
  46. package/src/events/EventEmittingComponent.ts +7 -0
  47. package/src/index.ts +7 -0
  48. package/src/trees/InMemoryMerkleTreeStorage.ts +17 -0
  49. package/src/trees/MerkleTreeStore.ts +5 -0
  50. package/src/trees/MockAsyncMerkleStore.ts +29 -0
  51. package/src/trees/RollupMerkleTree.ts +354 -0
  52. package/src/trees/VirtualMerkleTreeStore.ts +21 -0
  53. package/src/types.ts +12 -0
  54. package/src/zkProgrammable/ZkProgrammable.ts +5 -4
  55. package/src/zkProgrammable/provableMethod.ts +2 -2
  56. package/test/config/ContainerEvents.test.ts +86 -0
  57. package/test/config/ModuleContainer.test.ts +111 -6
  58. package/test/trees/MerkleTree.test.ts +105 -0
  59. package/dist/config/ChildContainerStartable.d.ts +0 -5
  60. package/dist/config/ChildContainerStartable.d.ts.map +0 -1
  61. /package/dist/{config/ChildContainerStartable.js → events/EventEmittingComponent.js} +0 -0
@@ -4,17 +4,38 @@ import "reflect-metadata";
4
4
  import {
5
5
  DependencyContainer,
6
6
  Frequency,
7
+ injectable,
7
8
  InjectionToken,
9
+ instancePerContainerCachingFactory,
10
+ isClassProvider,
11
+ isFactoryProvider,
12
+ isValueProvider,
8
13
  Lifecycle,
9
14
  } from "tsyringe";
10
15
  import log from "loglevel";
16
+ import merge from "lodash/merge";
11
17
 
12
- import { StringKeyOf, TypedClass } from "../types";
13
- import { DependencyFactory } from "../dependencyFactory/DependencyFactory";
18
+ import { MergeObjects, StringKeyOf, TypedClass } from "../types";
19
+ import {
20
+ DependencyFactory,
21
+ InferDependencies,
22
+ } from "../dependencyFactory/DependencyFactory";
14
23
 
15
- import { Configurable, ConfigurableModule } from "./ConfigurableModule";
24
+ import {
25
+ Configurable,
26
+ ConfigurableModule,
27
+ NoConfig,
28
+ } from "./ConfigurableModule";
16
29
  import { ChildContainerProvider } from "./ChildContainerProvider";
17
30
  import { ChildContainerCreatable } from "./ChildContainerCreatable";
31
+ import { EventEmitter } from "../events/EventEmitter";
32
+ import {
33
+ EventEmittingComponent,
34
+ EventsRecord,
35
+ } from "../events/EventEmittingComponent";
36
+ import { EventEmitterProxy } from "../events/EventEmitterProxy";
37
+ import { memoize } from "lodash";
38
+ import { Memoize } from "typescript-memoize";
18
39
 
19
40
  const errors = {
20
41
  configNotSetInContainer: (moduleName: string) =>
@@ -78,10 +99,16 @@ export type ModulesConfig<Modules extends ModulesRecord> = {
78
99
  [ConfigKey in StringKeyOf<Modules>]: InstanceType<
79
100
  Modules[ConfigKey]
80
101
  > extends Configurable<infer Config>
81
- ? Config
102
+ ? Config extends NoConfig
103
+ ? Config | undefined
104
+ : Config
82
105
  : never;
83
106
  };
84
107
 
108
+ export type RecursivePartial<T> = {
109
+ [Key in keyof T]?: T[Key] extends object ? RecursivePartial<T[Key]> : T[Key];
110
+ };
111
+
85
112
  /**
86
113
  * Parameters required when creating a module container instance
87
114
  */
@@ -91,6 +118,23 @@ export interface ModuleContainerDefinition<Modules extends ModulesRecord> {
91
118
  config?: ModulesConfig<Modules>;
92
119
  }
93
120
 
121
+ // Removes all keys with a "never" value from an object
122
+ export type FilterNeverValues<Type extends Record<string, unknown>> = {
123
+ [Key in keyof Type as Type[Key] extends never ? never : Key]: Type[Key];
124
+ };
125
+
126
+ export type DependenciesFromModules<Modules extends ModulesRecord> =
127
+ FilterNeverValues<{
128
+ [Key in keyof Modules]: Modules[Key] extends TypedClass<DependencyFactory>
129
+ ? InferDependencies<InstanceType<Modules[Key]>>
130
+ : never;
131
+ }>;
132
+
133
+ export type ResolvableModules<Modules extends ModulesRecord> = MergeObjects<
134
+ DependenciesFromModules<Modules>
135
+ > &
136
+ Modules;
137
+
94
138
  /**
95
139
  * Reusable module container facilitating registration, resolution
96
140
  * configuration, decoration and validation of modules
@@ -107,8 +151,13 @@ export class ModuleContainer<
107
151
  // DI container holding all the registered modules
108
152
  private providedContainer?: DependencyContainer = undefined;
109
153
 
154
+ private eventEmitterProxy: EventEmitterProxy<Modules> | undefined = undefined;
155
+
110
156
  public constructor(public definition: ModuleContainerDefinition<Modules>) {
111
157
  super();
158
+ if (definition.config !== undefined) {
159
+ this.config = definition.config;
160
+ }
112
161
  }
113
162
 
114
163
  /**
@@ -161,16 +210,16 @@ export class ModuleContainer<
161
210
  modules: Modules,
162
211
  moduleName: string
163
212
  ): asserts moduleName is StringKeyOf<Modules> {
164
- this.isValidModuleName(modules, moduleName);
213
+ if (!this.isValidModuleName(modules, moduleName)) {
214
+ throw errors.onlyValidModuleNames(moduleName);
215
+ }
165
216
  }
166
217
 
167
218
  public isValidModuleName(
168
219
  modules: Modules,
169
220
  moduleName: number | string | symbol
170
- ): asserts moduleName is StringKeyOf<Modules> {
171
- if (!Object.prototype.hasOwnProperty.call(modules, moduleName)) {
172
- throw errors.onlyValidModuleNames(moduleName);
173
- }
221
+ ): moduleName is StringKeyOf<Modules> {
222
+ return Object.prototype.hasOwnProperty.call(modules, moduleName);
174
223
  }
175
224
 
176
225
  public assertContainerInitialized(
@@ -207,16 +256,11 @@ export class ModuleContainer<
207
256
  }
208
257
  }
209
258
 
210
- /**
211
- * Inject a set of dependencies using the given list of DependencyFactories
212
- * This method should be called during startup
213
- */
214
- protected registerDependencyFactories(
215
- factories: TypedClass<DependencyFactory>[]
216
- ) {
217
- factories.forEach((factory) => {
218
- this.container.resolve(factory).initDependencies(this.container);
219
- });
259
+ public get events(): EventEmitterProxy<Modules> {
260
+ if (this.eventEmitterProxy === undefined) {
261
+ this.eventEmitterProxy = new EventEmitterProxy<Modules>(this);
262
+ }
263
+ return this.eventEmitterProxy;
220
264
  }
221
265
 
222
266
  /**
@@ -250,13 +294,22 @@ export class ModuleContainer<
250
294
  * @param config
251
295
  */
252
296
  public configure(config: ModulesConfig<Modules>) {
253
- this.definition.config = config;
297
+ this.config = config;
298
+ }
299
+
300
+ public configurePartial(config: RecursivePartial<ModulesConfig<Modules>>) {
301
+ this.config = merge<
302
+ ModulesConfig<Modules> | NoConfig,
303
+ RecursivePartial<ModulesConfig<Modules>>
304
+ >(this.currentConfig ?? {}, config);
254
305
  }
255
306
 
256
307
  // eslint-disable-next-line accessor-pairs
257
308
  public set config(config: ModulesConfig<Modules>) {
258
- super.config = config;
259
- this.definition.config = config;
309
+ super.config = merge<
310
+ ModulesConfig<Modules> | NoConfig,
311
+ ModulesConfig<Modules>
312
+ >(this.currentConfig ?? {}, config);
260
313
  }
261
314
 
262
315
  /**
@@ -269,12 +322,12 @@ export class ModuleContainer<
269
322
  * @param moduleName
270
323
  * @returns
271
324
  */
272
- public resolve<ResolvableModuleName extends StringKeyOf<Modules>>(
273
- moduleName: ResolvableModuleName
274
- ): InstanceType<Modules[ResolvableModuleName]> {
275
- return this.container.resolve<InstanceType<Modules[ResolvableModuleName]>>(
276
- moduleName
277
- );
325
+ public resolve<KeyType extends StringKeyOf<ResolvableModules<Modules>>>(
326
+ moduleName: KeyType
327
+ ): InstanceType<ResolvableModules<Modules>[KeyType]> {
328
+ return this.container.resolve<
329
+ InstanceType<ResolvableModules<Modules>[KeyType]>
330
+ >(moduleName);
278
331
  }
279
332
 
280
333
  public resolveOrFail<ModuleType>(
@@ -299,14 +352,77 @@ export class ModuleContainer<
299
352
  moduleName: StringKeyOf<Modules>,
300
353
  containedModule: InstanceType<Modules[StringKeyOf<Modules>]>
301
354
  ) {
302
- const config = this.definition.config?.[moduleName];
355
+ // Has to be super.config, getters behave really weird when subtyping
356
+ const config = super.config?.[moduleName];
303
357
 
304
358
  // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
305
359
  if (!config) {
306
360
  throw errors.configNotSetInContainer(moduleName.toString());
307
361
  }
308
362
 
309
- containedModule.config = config;
363
+ if (containedModule instanceof ModuleContainer) {
364
+ containedModule.configure(config);
365
+ } else {
366
+ containedModule.config = config;
367
+ }
368
+ }
369
+
370
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
371
+ private isDependencyFactory(type: any): type is DependencyFactory {
372
+ return "dependencies" in type;
373
+ }
374
+
375
+ /**
376
+ * Inject a set of dependencies using the given list of DependencyFactories
377
+ * This method should be called during startup
378
+ */
379
+ protected initializeDependencyFactories(factories: StringKeyOf<Modules>[]) {
380
+ factories.forEach((factoryName) => {
381
+ this.resolve(factoryName);
382
+ });
383
+ }
384
+
385
+ /**
386
+ * Retrieves all dependencies generated by a particular dependencyfactory
387
+ * and injects them inside this modulecontainer's DI container.
388
+ * This will be automatically called for every module, but can also be called
389
+ * explicitly to initialize an extra factory
390
+ * @param factory
391
+ * @private
392
+ */
393
+ protected useDependencyFactory(factory: DependencyFactory) {
394
+ const dependencies = factory.dependencies();
395
+
396
+ Object.entries(dependencies).forEach(([rawKey, declaration]) => {
397
+ const key = rawKey.charAt(0).toUpperCase() + rawKey.slice(1);
398
+
399
+ if (
400
+ !this.container.isRegistered(key) ||
401
+ declaration.forceOverwrite === true
402
+ ) {
403
+ // Find correct provider type and call respective register
404
+ if (isValueProvider(declaration)) {
405
+ this.container.register(key, declaration);
406
+ } else if (isFactoryProvider(declaration)) {
407
+ // this enables us to have a singletoned factory
408
+ // that returns the same instance for each resolve
409
+ this.container.register(key, {
410
+ useFactory: instancePerContainerCachingFactory(
411
+ declaration.useFactory
412
+ ),
413
+ });
414
+ } else if (isClassProvider(declaration)) {
415
+ this.container.register(key, declaration, {
416
+ lifecycle: Lifecycle.Singleton,
417
+ });
418
+ } else {
419
+ // Can never be reached
420
+ throw new Error("Above if-statement is exhaustive");
421
+ }
422
+ } else {
423
+ log.debug(`Dependency ${key} already registered, skipping`);
424
+ }
425
+ });
310
426
  }
311
427
 
312
428
  /**
@@ -328,6 +444,10 @@ export class ModuleContainer<
328
444
  container.reset();
329
445
  return container;
330
446
  });
447
+
448
+ if (this.isDependencyFactory(containedModule)) {
449
+ this.useDependencyFactory(containedModule);
450
+ }
331
451
  },
332
452
  { frequency: ModuleContainer.moduleDecorationFrequency }
333
453
  );
@@ -1,25 +1,21 @@
1
- import { DependencyContainer, injectable, Lifecycle } from "tsyringe";
1
+ import {
2
+ ClassProvider,
3
+ FactoryProvider,
4
+ ValueProvider,
5
+ } from "tsyringe";
2
6
 
3
7
  import { TypedClass } from "../types";
4
- import { log } from "../log";
8
+ import { BaseModuleInstanceType } from "../config/ModuleContainer";
5
9
 
6
- const errors = {
7
- descriptorUndefined: () =>
8
- new Error("Descriptor of that dependency is undefined!"),
10
+ export type DependencyDeclaration<Dependency> =
11
+ | ClassProvider<Dependency>
12
+ | FactoryProvider<Dependency>
13
+ | ValueProvider<Dependency>;
9
14
 
10
- dependencyFactoryCalledDirectly: () =>
11
- new Error(
12
- "You cannot access the depdendency method directly, use container.resolve"
13
- ),
14
- };
15
-
16
- const globalFactoryDependencies = new Map<
15
+ export type DependencyRecord = Record<
17
16
  string,
18
- | {
19
- [key: string]: () => unknown;
20
- }
21
- | undefined
22
- >();
17
+ DependencyDeclaration<unknown> & { forceOverwrite?: boolean }
18
+ >;
23
19
 
24
20
  /**
25
21
  * This is an abstract class for creating DependencyFactories, a pattern
@@ -32,105 +28,20 @@ const globalFactoryDependencies = new Map<
32
28
  *
33
29
  * DependencyFactories are designed to only be used statically for sets of
34
30
  * deps that are necessary for the sequencer to work.
35
- *
36
- * Every Factory need the @dependencyFactory annotation (which basically
37
- * proxies @injectable()) and every method that returns a dependency has to be
38
- * of the format `() => Dependency` and be annotated with @dependency.
39
31
  */
40
- export abstract class DependencyFactory {
41
- public initDependencies(container: DependencyContainer) {
42
- const dependencies =
43
- globalFactoryDependencies.get(this.constructor.name) ?? {};
44
-
45
- for (const [key, useFactory] of Object.entries(dependencies)) {
46
- container.register(`${key}_singleton-prototype`, {
47
- useFactory: useFactory.bind(this),
48
- });
49
-
50
- const upperCaseKey = key.charAt(0).toUpperCase() + key.slice(1);
51
-
52
- container.register(
53
- upperCaseKey,
54
- {
55
- useToken: `${key}_singleton-prototype`,
56
- },
57
- { lifecycle: Lifecycle.ContainerScoped }
58
- );
59
-
60
- log.debug(
61
- `Registered dependency ${upperCaseKey} from factory ${this.constructor.name}`
62
- );
63
- }
64
- }
32
+ export interface DependencyFactory {
33
+ dependencies: () => DependencyRecord;
65
34
  }
66
35
 
67
- // type DTypes = { [key: string]: TypedClass<unknown> }
68
- // type Factories<T extends DTypes> = {
69
- // [key in keyof T]: T[key] extends TypedClass<infer R> ? () => R : never
70
- // }
71
- //
72
- // export abstract class DF2<Types extends DTypes> {
73
- // public constructor(private factories: Factories<Types>) {
74
- //
75
- // }
76
- // generateDependencies(): Types {
77
- // let x = this.factories;
78
- // return {} as Types;
79
- // }
80
- // }
36
+ export type TypeFromDependencyDeclaration<
37
+ Declaration extends DependencyDeclaration<unknown>
38
+ > = Declaration extends DependencyDeclaration<infer Dependency> ? Dependency : never;
81
39
 
82
- // export function DF2C<T extends Types>(object: Factories<T>): T {
83
- // const c = class C extends DF2<T>{
84
- // generateDependencies(): T {
85
- // return undefined;
86
- // }
87
- // }
88
- // return new c();
89
- // }
90
-
91
- // class DF2I extends DF2<{x: typeof ConfigurableModule}> {
92
- // constructor() {
93
- // super({
94
- // x: this.x
95
- // });
96
- // }
97
- //
98
- // x(): ConfigurableModule<any> {
99
- // return {} as ConfigurableModule<any>;
100
- // }
101
- //
102
- // }
103
-
104
- export function dependency() {
105
- return function decorator<Target extends DependencyFactory, Dependency>(
106
- target: Target,
107
- key: string,
108
- descriptor: TypedPropertyDescriptor<() => Dependency>
109
- ) {
110
- if (descriptor.value !== undefined) {
111
- const className = target.constructor.name;
112
- if (!globalFactoryDependencies.has(className)) {
113
- globalFactoryDependencies.set(className, {});
114
- }
115
-
116
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
117
- globalFactoryDependencies.get(target.constructor.name)![key] =
118
- descriptor.value;
119
-
120
- descriptor.value = () => {
121
- throw errors.dependencyFactoryCalledDirectly();
122
- };
123
- } else {
124
- throw errors.descriptorUndefined();
125
- }
126
- return descriptor;
127
- };
128
- }
40
+ export type MapDependencyRecordToTypes<Record extends DependencyRecord> = {
41
+ [Key in keyof Record]: TypedClass<TypeFromDependencyDeclaration<Record[Key]>>;
42
+ };
129
43
 
130
- export function dependencyFactory() {
131
- return function decorator<Target extends DependencyFactory>(
132
- target: TypedClass<Target>
133
- ) {
134
- injectable()(target);
135
- };
136
- }
44
+ export type InferDependencies<Class extends BaseModuleInstanceType> =
45
+ Class extends DependencyFactory
46
+ ? MapDependencyRecordToTypes<ReturnType<Class["dependencies"]>>
47
+ : never;
@@ -0,0 +1,58 @@
1
+ import { EventsRecord } from "./EventEmittingComponent";
2
+
3
+ type ListenersHolder<Events extends EventsRecord> = {
4
+ // eslint-disable-next-line putout/putout
5
+ [key in keyof Events]?: ((...args: Events[key]) => void)[];
6
+ };
7
+
8
+ export class EventEmitter<Events extends EventsRecord> {
9
+ private readonly listeners: ListenersHolder<Events> = {};
10
+
11
+ // eslint-disable-next-line putout/putout
12
+ private readonly wildcardListeners: ((
13
+ event: keyof Events,
14
+ args: Events[keyof Events]
15
+ ) => void)[] = [];
16
+
17
+ public emit<Key extends keyof Events>(
18
+ event: Key,
19
+ ...parameters: Events[Key]
20
+ ) {
21
+ const listeners = this.listeners[event];
22
+ if (listeners !== undefined) {
23
+ listeners.forEach((listener) => {
24
+ listener(...parameters);
25
+ });
26
+ }
27
+ this.wildcardListeners.forEach((wildcardListener) => {
28
+ wildcardListener(event, parameters);
29
+ });
30
+ }
31
+
32
+ public onAll(listener: (event: keyof Events, args: unknown[]) => void): void {
33
+ this.wildcardListeners.push(listener);
34
+ }
35
+
36
+ public on<Key extends keyof Events>(
37
+ event: Key,
38
+ listener: (...args: Events[Key]) => void
39
+ ) {
40
+ (this.listeners[event] ??= []).push(listener);
41
+ }
42
+
43
+ /**
44
+ * Primitive .off() with identity comparison for now.
45
+ * Could be replaced by returning an id in .on() and using that.
46
+ */
47
+ public off<Key extends keyof Events>(
48
+ event: Key,
49
+ listener: (...args: Events[Key]) => void
50
+ ) {
51
+ const events = this.listeners[event];
52
+ if (events !== undefined) {
53
+ this.listeners[event] = events.filter(
54
+ (candidate) => candidate !== listener
55
+ );
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,57 @@
1
+ import type {
2
+ BaseModuleType,
3
+ ModuleContainer,
4
+ ModulesRecord,
5
+ } from "../config/ModuleContainer";
6
+ import { StringKeyOf, UnionToIntersection } from "../types";
7
+
8
+ import { EventEmitter } from "./EventEmitter";
9
+ import { EventEmittingComponent, EventsRecord } from "./EventEmittingComponent";
10
+
11
+ export type CastToEventsRecord<Record> = Record extends EventsRecord
12
+ ? Record
13
+ : {};
14
+
15
+ export type ModuleEvents<ModuleType extends BaseModuleType> =
16
+ InstanceType<ModuleType> extends EventEmittingComponent<infer Events>
17
+ ? Events
18
+ : InstanceType<ModuleType> extends ModuleContainer<infer NestedModules>
19
+ ? CastToEventsRecord<ContainerEvents<NestedModules>>
20
+ : EventsRecord;
21
+
22
+ export type ContainerEvents<Modules extends ModulesRecord> = {
23
+ [Key in StringKeyOf<Modules>]: ModuleEvents<Modules[Key]>;
24
+ };
25
+
26
+ export type FlattenObject<Target extends Record<string, EventsRecord>> =
27
+ UnionToIntersection<Target[keyof Target]>;
28
+
29
+ export type FlattenedContainerEvents<Modules extends ModulesRecord> =
30
+ FlattenObject<ContainerEvents<Modules>>;
31
+
32
+ export class EventEmitterProxy<
33
+ Modules extends ModulesRecord
34
+ > extends EventEmitter<CastToEventsRecord<FlattenedContainerEvents<Modules>>> {
35
+ public constructor(private readonly container: ModuleContainer<Modules>) {
36
+ super();
37
+ container.moduleNames.forEach((moduleName) => {
38
+ if (
39
+ container.isValidModuleName(container.definition.modules, moduleName)
40
+ ) {
41
+ const module = container.resolve(moduleName);
42
+ if (this.isEventEmitter(module)) {
43
+ module.events.onAll((events: any, args: unknown[]) => {
44
+ this.emit(events, ...(args as any));
45
+ });
46
+ }
47
+ }
48
+ });
49
+ }
50
+
51
+ private isEventEmitter(
52
+ module: any
53
+ ): module is EventEmittingComponent<EventsRecord> {
54
+ const emitter = module.events;
55
+ return emitter !== undefined && emitter instanceof EventEmitter;
56
+ }
57
+ }
@@ -0,0 +1,7 @@
1
+ import type { EventEmitter } from "./EventEmitter";
2
+
3
+ export type EventsRecord = Record<string, unknown[]>;
4
+
5
+ export interface EventEmittingComponent<Events extends EventsRecord> {
6
+ events: EventEmitter<Events>;
7
+ }
package/src/index.ts CHANGED
@@ -9,3 +9,10 @@ export * from "./zkProgrammable/provableMethod";
9
9
  export * from "./utils";
10
10
  export * from "./dependencyFactory/DependencyFactory";
11
11
  export * from "./log";
12
+ export * from "./events/EventEmittingComponent";
13
+ export * from "./events/EventEmitter";
14
+ export * from "./trees/MerkleTreeStore";
15
+ export * from "./trees/InMemoryMerkleTreeStorage";
16
+ export * from "./trees/RollupMerkleTree";
17
+ export * from "./events/EventEmitterProxy";
18
+ export * from "./trees/MockAsyncMerkleStore";
@@ -0,0 +1,17 @@
1
+ import { MerkleTreeStore } from "./MerkleTreeStore";
2
+
3
+ export class InMemoryMerkleTreeStorage implements MerkleTreeStore {
4
+ protected nodes: {
5
+ [key: number]: {
6
+ [key: string]: bigint;
7
+ };
8
+ } = {};
9
+
10
+ public getNode(key: bigint, level: number): bigint | undefined {
11
+ return this.nodes[level]?.[key.toString()];
12
+ }
13
+
14
+ public setNode(key: bigint, level: number, value: bigint): void {
15
+ (this.nodes[level] ??= {})[key.toString()] = value;
16
+ }
17
+ }
@@ -0,0 +1,5 @@
1
+ export interface MerkleTreeStore {
2
+ setNode: (key: bigint, level: number, value: bigint) => void;
3
+
4
+ getNode: (key: bigint, level: number) => bigint | undefined;
5
+ }
@@ -0,0 +1,29 @@
1
+ import { InMemoryMerkleTreeStorage } from "./InMemoryMerkleTreeStorage";
2
+ import { noop } from "./../utils";
3
+
4
+ export class MockAsyncMerkleTreeStore {
5
+ public readonly store = new InMemoryMerkleTreeStorage();
6
+
7
+ public commit(): void {
8
+ noop();
9
+ }
10
+
11
+ public openTransaction(): void {
12
+ noop();
13
+ }
14
+
15
+ public async getNodeAsync(
16
+ key: bigint,
17
+ level: number
18
+ ): Promise<bigint | undefined> {
19
+ return this.store.getNode(key, level);
20
+ }
21
+
22
+ public async setNodeAsync(
23
+ key: bigint,
24
+ level: number,
25
+ value: bigint
26
+ ): Promise<void> {
27
+ this.store.setNode(key, level, value);
28
+ }
29
+ }