@wirestate/core 0.6.1 → 0.7.0-experimental.1

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 (167) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/README.md +186 -232
  3. package/cjs/development/index.js +325 -91
  4. package/cjs/development/index.js.map +1 -1
  5. package/cjs/development/lib.js +1033 -248
  6. package/cjs/development/lib.js.map +1 -1
  7. package/cjs/development/test-utils.js +95 -32
  8. package/cjs/development/test-utils.js.map +1 -1
  9. package/cjs/production/index.js +1 -1
  10. package/cjs/production/index.js.map +1 -1
  11. package/cjs/production/lib.js +1 -1
  12. package/cjs/production/lib.js.map +1 -1
  13. package/cjs/production/test-utils.js +1 -1
  14. package/cjs/production/test-utils.js.map +1 -1
  15. package/esm/development/alias.js +10 -1
  16. package/esm/development/alias.js.map +1 -1
  17. package/esm/development/bind/bind-constant.js +25 -4
  18. package/esm/development/bind/bind-constant.js.map +1 -1
  19. package/esm/development/bind/bind-dynamic-value.js +27 -7
  20. package/esm/development/bind/bind-dynamic-value.js.map +1 -1
  21. package/esm/development/bind/bind-entry.js +50 -17
  22. package/esm/development/bind/bind-entry.js.map +1 -1
  23. package/esm/development/bind/bind-service.js +71 -19
  24. package/esm/development/bind/bind-service.js.map +1 -1
  25. package/esm/development/bind/get-entry-token.js +21 -5
  26. package/esm/development/bind/get-entry-token.js.map +1 -1
  27. package/esm/development/commands/command-bus.js +93 -46
  28. package/esm/development/commands/command-bus.js.map +1 -1
  29. package/esm/development/commands/command-optional.js +28 -5
  30. package/esm/development/commands/command-optional.js.map +1 -1
  31. package/esm/development/commands/command.js +26 -5
  32. package/esm/development/commands/command.js.map +1 -1
  33. package/esm/development/commands/get-command-handler-metadata.js +8 -3
  34. package/esm/development/commands/get-command-handler-metadata.js.map +1 -1
  35. package/esm/development/commands/on-command.js +19 -3
  36. package/esm/development/commands/on-command.js.map +1 -1
  37. package/esm/development/container/create-base-container.js +57 -0
  38. package/esm/development/container/create-base-container.js.map +1 -0
  39. package/esm/development/container/create-container.js +78 -0
  40. package/esm/development/container/create-container.js.map +1 -0
  41. package/esm/development/container/wire-scope.js +236 -54
  42. package/esm/development/container/wire-scope.js.map +1 -1
  43. package/esm/development/error/error-code.js +2 -1
  44. package/esm/development/error/error-code.js.map +1 -1
  45. package/esm/development/error/wirestate-error.js +25 -4
  46. package/esm/development/error/wirestate-error.js.map +1 -1
  47. package/esm/development/events/build-event-dispatcher.js +20 -2
  48. package/esm/development/events/build-event-dispatcher.js.map +1 -1
  49. package/esm/development/events/emit-event.js +18 -5
  50. package/esm/development/events/emit-event.js.map +1 -1
  51. package/esm/development/events/event-bus.js +58 -9
  52. package/esm/development/events/event-bus.js.map +1 -1
  53. package/esm/development/events/get-event-handler-metadata.js +19 -4
  54. package/esm/development/events/get-event-handler-metadata.js.map +1 -1
  55. package/esm/development/events/on-event.js +31 -2
  56. package/esm/development/events/on-event.js.map +1 -1
  57. package/esm/development/index.js +5 -4
  58. package/esm/development/index.js.map +1 -1
  59. package/esm/development/queries/get-query-handler-metadata.js +20 -4
  60. package/esm/development/queries/get-query-handler-metadata.js.map +1 -1
  61. package/esm/development/queries/on-query.js +24 -2
  62. package/esm/development/queries/on-query.js.map +1 -1
  63. package/esm/development/queries/query-bus.js +82 -31
  64. package/esm/development/queries/query-bus.js.map +1 -1
  65. package/esm/development/queries/query-optional.js +19 -5
  66. package/esm/development/queries/query-optional.js.map +1 -1
  67. package/esm/development/queries/query.js +25 -5
  68. package/esm/development/queries/query.js.map +1 -1
  69. package/esm/development/registry.js +81 -24
  70. package/esm/development/registry.js.map +1 -1
  71. package/esm/development/seeds/apply-seeds.js +19 -5
  72. package/esm/development/seeds/apply-seeds.js.map +1 -1
  73. package/esm/development/seeds/apply-shared-seed.js +16 -4
  74. package/esm/development/seeds/apply-shared-seed.js.map +1 -1
  75. package/esm/development/seeds/tokens.js +31 -0
  76. package/esm/development/seeds/tokens.js.map +1 -0
  77. package/esm/development/seeds/unapply-seeds.js +16 -5
  78. package/esm/development/seeds/unapply-seeds.js.map +1 -1
  79. package/esm/development/service/get-activated-handler-metadata.js +16 -4
  80. package/esm/development/service/get-activated-handler-metadata.js.map +1 -1
  81. package/esm/development/service/get-deactivation-handler-metadata.js +16 -4
  82. package/esm/development/service/get-deactivation-handler-metadata.js.map +1 -1
  83. package/esm/development/service/on-activated.js +22 -2
  84. package/esm/development/service/on-activated.js.map +1 -1
  85. package/esm/development/service/on-deactivation.js +22 -2
  86. package/esm/development/service/on-deactivation.js.map +1 -1
  87. package/esm/development/test-utils/mock-bind-entry.js +17 -7
  88. package/esm/development/test-utils/mock-bind-entry.js.map +1 -1
  89. package/esm/development/test-utils/mock-bind-service.js +17 -7
  90. package/esm/development/test-utils/mock-bind-service.js.map +1 -1
  91. package/esm/development/test-utils/mock-container.js +25 -8
  92. package/esm/development/test-utils/mock-container.js.map +1 -1
  93. package/esm/development/test-utils/mock-service.js +18 -5
  94. package/esm/development/test-utils/mock-service.js.map +1 -1
  95. package/esm/development/test-utils/mock-unbind-service.js +16 -3
  96. package/esm/development/test-utils/mock-unbind-service.js.map +1 -1
  97. package/esm/development/types/commands.js +6 -1
  98. package/esm/development/types/commands.js.map +1 -1
  99. package/esm/production/alias.js +1 -1
  100. package/esm/production/alias.js.map +1 -1
  101. package/esm/production/bind/bind-constant.js +1 -1
  102. package/esm/production/bind/bind-constant.js.map +1 -1
  103. package/esm/production/bind/bind-dynamic-value.js +1 -1
  104. package/esm/production/bind/bind-dynamic-value.js.map +1 -1
  105. package/esm/production/bind/bind-entry.js +1 -1
  106. package/esm/production/bind/bind-entry.js.map +1 -1
  107. package/esm/production/bind/bind-service.js.map +1 -1
  108. package/esm/production/bind/get-entry-token.js.map +1 -1
  109. package/esm/production/commands/command-bus.js +1 -1
  110. package/esm/production/commands/command-bus.js.map +1 -1
  111. package/esm/production/commands/command-optional.js.map +1 -1
  112. package/esm/production/commands/command.js.map +1 -1
  113. package/esm/production/commands/get-command-handler-metadata.js.map +1 -1
  114. package/esm/production/commands/on-command.js.map +1 -1
  115. package/esm/production/container/create-base-container.js +1 -0
  116. package/esm/production/container/create-base-container.js.map +1 -0
  117. package/esm/production/container/create-container.js +1 -0
  118. package/esm/production/container/create-container.js.map +1 -0
  119. package/esm/production/container/wire-scope.js +1 -1
  120. package/esm/production/container/wire-scope.js.map +1 -1
  121. package/esm/production/error/error-code.js +1 -1
  122. package/esm/production/error/error-code.js.map +1 -1
  123. package/esm/production/error/wirestate-error.js.map +1 -1
  124. package/esm/production/events/build-event-dispatcher.js.map +1 -1
  125. package/esm/production/events/emit-event.js.map +1 -1
  126. package/esm/production/events/event-bus.js +1 -1
  127. package/esm/production/events/event-bus.js.map +1 -1
  128. package/esm/production/events/get-event-handler-metadata.js.map +1 -1
  129. package/esm/production/events/on-event.js.map +1 -1
  130. package/esm/production/index.js +1 -1
  131. package/esm/production/queries/get-query-handler-metadata.js.map +1 -1
  132. package/esm/production/queries/on-query.js.map +1 -1
  133. package/esm/production/queries/query-bus.js +1 -1
  134. package/esm/production/queries/query-bus.js.map +1 -1
  135. package/esm/production/queries/query-optional.js.map +1 -1
  136. package/esm/production/queries/query.js.map +1 -1
  137. package/esm/production/registry.js +1 -1
  138. package/esm/production/registry.js.map +1 -1
  139. package/esm/production/seeds/apply-seeds.js +1 -1
  140. package/esm/production/seeds/apply-seeds.js.map +1 -1
  141. package/esm/production/seeds/apply-shared-seed.js +1 -1
  142. package/esm/production/seeds/apply-shared-seed.js.map +1 -1
  143. package/esm/production/seeds/tokens.js +1 -0
  144. package/esm/production/seeds/tokens.js.map +1 -0
  145. package/esm/production/seeds/unapply-seeds.js +1 -1
  146. package/esm/production/seeds/unapply-seeds.js.map +1 -1
  147. package/esm/production/service/get-activated-handler-metadata.js.map +1 -1
  148. package/esm/production/service/get-deactivation-handler-metadata.js.map +1 -1
  149. package/esm/production/service/on-activated.js.map +1 -1
  150. package/esm/production/service/on-deactivation.js.map +1 -1
  151. package/esm/production/test-utils/mock-bind-entry.js +1 -1
  152. package/esm/production/test-utils/mock-bind-entry.js.map +1 -1
  153. package/esm/production/test-utils/mock-bind-service.js +1 -1
  154. package/esm/production/test-utils/mock-bind-service.js.map +1 -1
  155. package/esm/production/test-utils/mock-container.js +1 -1
  156. package/esm/production/test-utils/mock-container.js.map +1 -1
  157. package/esm/production/test-utils/mock-service.js.map +1 -1
  158. package/esm/production/test-utils/mock-unbind-service.js.map +1 -1
  159. package/esm/production/types/commands.js.map +1 -1
  160. package/index.d.ts +1159 -229
  161. package/lib.d.ts +128 -9
  162. package/package.json +1 -2
  163. package/test-utils.d.ts +140 -40
  164. package/esm/development/container/create-ioc-container.js +0 -35
  165. package/esm/development/container/create-ioc-container.js.map +0 -1
  166. package/esm/production/container/create-ioc-container.js +0 -1
  167. package/esm/production/container/create-ioc-container.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ ## 0.7.0
2
+
3
+ - Add `useScope` in `@wirestate/react`
4
+ - New lit elements modules - `@wirestate/lit` and `@wirestate/lit-signals`
5
+ - `EventBus`: add `unsubscribe` method for explicit handler removal by reference
6
+ - `QueryBus`: add `unregister` method for explicit handler removal by type and reference
7
+ - `CommandBus`: add `unregister` method for explicit handler removal by type and reference
8
+ - `WireScope`: add new event/command/query subscribe-unsubscribe methods
9
+ - Export more alias / methods from `@wirestate/core`
10
+ - Export more alias / methods from `@wirestate/react-mobx`
11
+ - Export missing methods typing for `@wirestate/core`
12
+ - Extensive JSDoc coverage for wirestate packages
13
+ - `createIocContainer`: Added ability to instantly provide and activate entries, targeted seeds
14
+ - `createInjectablesProvider`: Removed.
15
+ - `IocProvider`: Removed
16
+ - `useRootContainer`: Added separate hook for store management in React tree
17
+ - `ContainerProvider`: Simpler provider for containers.
18
+ - `SubContainerProvider`: Added component solving problems of removed `createInjectablesProvider`
19
+ - `ContainerActivator`: Added separate activation component
20
+
21
+ ## 0.6.3
22
+
23
+ - Update readme files for each module
24
+
25
+ ## 0.6.2
26
+
27
+ - Corrected build system, react package structure
28
+
1
29
  ## 0.6.1
2
30
 
3
31
  - React related types moved to react lib
@@ -51,6 +79,6 @@
51
79
  - useService -> useInjection
52
80
  - AbstractService::getService -> AbstractService::resolve
53
81
 
54
- ## 0.1.1
82
+ ## 0.1.0
55
83
 
56
84
  - Initial release
package/README.md CHANGED
@@ -1,317 +1,271 @@
1
- # <a href='https://www.npmjs.com/package/wirestate'> wirestate </a>
1
+ # @wirestate/core [[monorepo](https://github.com/Neloreck/wirestate)] [[docs](https://neloreck.github.io/wirestate/)]
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/wirestate.svg?style=flat-square)](https://www.npmjs.com/package/wirestate)
4
- [![language-ts](https://img.shields.io/badge/language-typescript-blue.svg?style=flat)](https://github.com/Neloreck/wirestate/search?l=typescript)
3
+ [![npm](https://img.shields.io/npm/v/@wirestate/core.svg?style=flat-square)](https://www.npmjs.com/package/@wirestate/core)
5
4
  [![license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/Neloreck/wirestate/blob/master/LICENSE)
6
5
 
7
- `wirestate` is a reactivity-independent state management framework for React. It integrates **InversifyJS** for robust Dependency Injection,
8
- providing IOC/DI/indirection based architecture based on concepts of Services, Events, Commands, and Queries.
6
+ Core package for wirestate.
7
+ Provides the DI container, service primitives, and event/command/query buses.
8
+ React integration is in [`@wirestate/react`](https://www.npmjs.com/package/@wirestate/react).
9
9
 
10
- It optionally works with **MobX**, **Signals**, or other custom reactivity implementations.
10
+ ## Installation
11
11
 
12
- ## Architecture & Core Concepts
12
+ ```bash
13
+ npm install @wirestate/core reflect-metadata
14
+ ```
13
15
 
14
- Designed for complex applications, `wirestate` enforces a clear separation of concerns:
16
+ Import `reflect-metadata` once at your application entry point, before any wirestate imports:
15
17
 
16
- - **Services**: Singleton-scoped logic units that hold state and business logic.
17
- - **Dependency Injection**: First-class InversifyJS integration for decoupled, testable code.
18
- - **Reactivity**: Independent state tracking (optional integration with MobX, Signals, etc.).
19
- - **Events**: Fire-and-forget communication for cross-service side effects.
20
- - **Commands**: Encapsulated write operations with standardized execution status (pending, settled, error).
21
- - **Queries**: Synchronous or asynchronous request-response patterns for data retrieval.
22
- - **Lifecycle Management**: Automated services provision within react tree, activation/deactivation lifecycle.
18
+ ```ts
19
+ import "reflect-metadata";
20
+ ```
23
21
 
24
- ## Requirements
22
+ ## Services
25
23
 
26
- - `react >= 16.8.0`
27
- - `reflect-metadata` (must be imported at application entry)
24
+ Services are plain classes decorated with `@Injectable`. Each service may inject a `WireScope` which provides access to the event, command, and query buses and to other services in the container.
28
25
 
29
- ## Installation
26
+ ```ts
27
+ import { Injectable, Inject, WireScope } from "@wirestate/core";
30
28
 
31
- ```bash
32
- npm install --save @wirestate/core reflect-metadata
33
- ```
29
+ @Injectable()
30
+ export class CounterService {
31
+ public count = 0;
34
32
 
35
- ### For react-mobx
33
+ public constructor(@Inject(WireScope) private scope: WireScope) {}
36
34
 
37
- ```bash
38
- npm install --save @wirestate/react @wirestate/react-mobx mobx mobx-react-lite
35
+ public increment(): void {
36
+ this.count++;
37
+ }
38
+ }
39
39
  ```
40
40
 
41
- ### For signals
41
+ ## Container
42
42
 
43
- ```bash
44
- npm install --save @wirestate/react @wirestate/react-signals @preact/signals-react
45
- npm install --save-dev @preact/signals-react-transform
46
- ```
43
+ ```ts
44
+ import { createIocContainer, bindService } from "@wirestate/core";
47
45
 
48
- ## Quick Start with mobx
46
+ const container = createIocContainer({
47
+ seed: { baseUrl: "https://example.com" },
48
+ entries: [CounterService],
49
+ });
49
50
 
50
- ### 1. Define a Service
51
+ bindService(container, AnotherService);
51
52
 
52
- Services are standard classes decorated with `@Injectable`. Use `WireScope` to interact with the framework.
53
+ const counterService = container.get(CounterService);
54
+ const anotherService = container.get(AnotherService);
55
+ ```
53
56
 
54
- ```typescript
55
- import { Injectable, Inject, WireScope, OnEvent, OnCommand, OnQuery } from '@wirestate/core';
56
- import { makeObservable, Observable, Action } from '@wirestate/react-mobx';
57
+ `bindService` binds a class in singleton scope by default.
58
+ Use `bindConstant` to bind a value, `bindEntry` to bind under a custom token.
57
59
 
58
- @Injectable()
59
- export class CounterService {
60
- @Observable()
61
- public count: number = 0;
62
-
63
- public constructor(
64
- @Inject(WireScope)
65
- private scope: WireScope
66
- ) {
67
- makeObservable(this);
68
- }
60
+ ## Events
69
61
 
70
- @Action()
71
- public increment(amount: number = 1): void {
72
- this.count += amount;
73
- }
62
+ Events are fire-and-forget messages. Any service can emit or subscribe.
74
63
 
75
- @Action()
76
- public reset(): void {
77
- this.count = 0;
78
- }
64
+ ```ts
65
+ import { OnEvent, WireScope, Inject } from "@wirestate/core";
79
66
 
80
- @OnCommand('INCREMENT')
81
- public onIncrementCommand(amount: number = 1): void {
82
- this.increment(amount);
83
- }
67
+ @Injectable()
68
+ export class SenderService {
69
+ public constructor(@Inject(WireScope) private scope: WireScope) {}
84
70
 
85
- @OnQuery('GET_TOTAL')
86
- public onGetTotal(): number {
87
- return this.count;
71
+ public notify(): void {
72
+ this.scope.emitEvent("USER_LOGGED_OUT");
88
73
  }
74
+ }
89
75
 
90
- @OnEvent('RESET')
91
- public onResetEvent(): void {
92
- this.reset();
76
+ @Injectable()
77
+ export class ReceiverService {
78
+ @OnEvent("USER_LOGGED_OUT")
79
+ public onLogout(): void {
80
+ // handle logout
93
81
  }
94
82
  }
95
83
  ```
96
84
 
97
- ### 2. Configure the Provider
85
+ `@OnEvent()` with no argument subscribes to all events.
98
86
 
99
- Bind services at any level of the component tree.
100
- Lifetimes are managed automatically.
87
+ ## Commands
101
88
 
102
- ```tsx
103
- import { IocProvider, createInjectablesProvider } from '@wirestate/react';
104
- import { CounterService } from './CounterService';
89
+ Commands are write operations dispatched by token. A single handler is expected per command type.
105
90
 
106
- const MainProvider = createInjectablesProvider([CounterService]);
91
+ ```ts
92
+ import { OnCommand, WireScope, Inject } from "@wirestate/core";
107
93
 
108
- export function Application() {
109
- return (
110
- <IocProvider>
111
- <MainProvider>
112
- <CounterView />
113
- </MainProvider>
114
- </IocProvider>
115
- );
94
+ @Injectable()
95
+ export class AuthService {
96
+ @OnCommand("LOGIN")
97
+ public async onLogin(payload: { username: string }): Promise<void> {
98
+ // perform login
99
+ }
116
100
  }
117
- ```
118
101
 
119
- ### 3. Consume in Components
120
-
121
- Directly use services and rely on mobx reactivity.
122
- Or use specialized hooks for communication without direct references.
123
-
124
- ```tsx
125
- import { useInjection, useCommandCaller, useEventEmitter } from '@wirestate/react';
126
- import { observer } from '@wirestate/react-mobx';
127
- import { CounterService } from './CounterService';
128
-
129
- export const CounterView = observer(() => {
130
- const service = useInjection(CounterService);
131
- const call = useCommandCaller();
132
- const emit = useEventEmitter();
133
-
134
- return (
135
- <div>
136
- <p>Count: {service.count}</p>
137
- <button onClick={() => service.increment(5)}>Add 1 (Method)</button>
138
- <button onClick={() => call('INCREMENT', 5)}>Add 5 (Command)</button>
139
- <button onClick={() => service.reset()}>Reset (Method)</button>
140
- <button onClick={() => emit('RESET')}>Reset (Event)</button>
141
- </div>
142
- );
143
- });
102
+ @Injectable()
103
+ export class AnotherService {
104
+ public constructor(@Inject(WireScope) private scope: WireScope) {}
105
+
106
+ public async login(): Promise<void> {
107
+ await this.scope.executeCommand("LOGIN").task;
108
+ }
109
+ }
144
110
  ```
145
111
 
146
- ## Quick Start with signals
112
+ Use `commandOptional` when a handler may not be registered — returns `null` instead of throwing.
147
113
 
148
- ### 1. Define a Service
114
+ ## Queries
149
115
 
150
- Services use `signal` and `computed` for state management.
116
+ Queries are request-response operations. A single handler is expected per query type.
151
117
 
152
- ```typescript
153
- import { Injectable, Inject, WireScope, OnEvent, OnCommand, OnQuery } from '@wirestate/core';
154
- import { signal, computed, Signal, ReadonlySignal } from '@wirestate/react-signals';
118
+ ```ts
119
+ import { OnQuery, WireScope, Inject } from "@wirestate/core";
155
120
 
156
121
  @Injectable()
157
- export class CounterService {
158
- public readonly count: Signal<number> = signal(0);
159
- public readonly isEven: ReadonlySignal<boolean> = computed(() => this.count.value % 2 === 0);
122
+ export class StoreService {
123
+ private items: Array<string> = [];
160
124
 
161
- public constructor(
162
- @Inject(WireScope)
163
- private scope: WireScope
164
- ) {}
165
-
166
- public increment(amount: number = 1): void {
167
- this.count.value += amount;
168
- }
169
-
170
- public reset(): void {
171
- this.count.value = 0;
172
- }
173
-
174
- @OnCommand('INCREMENT')
175
- public onIncrementCommand(amount: number = 1): void {
176
- this.increment(amount);
125
+ @OnQuery("STORE_ITEMS")
126
+ public onGetItems(): Array<string> {
127
+ return this.items;
177
128
  }
129
+ }
178
130
 
179
- @OnQuery('GET_TOTAL')
180
- public onGetTotal(): number {
181
- return this.count.value;
182
- }
131
+ @Injectable()
132
+ export class AnotherService {
133
+ public constructor(@Inject(WireScope) private scope: WireScope) {}
183
134
 
184
- @OnEvent('RESET')
185
- public onResetEvent(): void {
186
- this.reset();
135
+ public async someActionRequiringItems(): Promise<void> {
136
+ const asyncItems: Array<string> = await this.scope.queryData("STORE_ITEMS");
137
+ const syncItems: Array<string> = await this.scope.queryData("STORE_ITEMS");
187
138
  }
188
139
  }
189
140
  ```
190
141
 
191
- ### 2. Configure the Provider
192
-
193
- The provider configuration remains the same regardless of the reactivity implementation.
142
+ ## Seeds
194
143
 
195
- ```tsx
196
- import { IocProvider, createInjectablesProvider } from '@wirestate/react';
197
- import { CounterService } from './CounterService';
144
+ Seeds pass initial data to services when they are activated.
198
145
 
199
- const MainProvider = createInjectablesProvider([CounterService]);
146
+ ```ts
147
+ import { SEED, Injectable, Inject } from "@wirestate/core";
200
148
 
201
- export function Application() {
202
- return (
203
- <IocProvider>
204
- <MainProvider>
205
- <CounterView />
206
- </MainProvider>
207
- </IocProvider>
208
- );
149
+ // Shared seed — same object injected into all services in the tree:
150
+ @Injectable()
151
+ export class MyService {
152
+ public constructor(@Inject(SEED) private seed: { theme: string }) {}
209
153
  }
210
- ```
211
154
 
212
- ### 3. Consume in Components
213
-
214
- Access signals directly in components. Reactivity is handled by the signals transform or manual subscription.
215
-
216
- ```tsx
217
- import { useInjection, useCommandCaller, useEventEmitter } from '@wirestate/react';
218
- import { CounterService } from './CounterService';
219
-
220
- export function CounterView() {
221
- const service = useInjection(CounterService);
222
- const call = useCommandCaller();
223
- const emit = useEventEmitter();
224
-
225
- return (
226
- <div>
227
- <p>Count: {service.count}</p>
228
- <p>Even: {service.isEven.value ? 'Yes' : 'No'}</p>
229
- <button onClick={() => service.increment(5)}>Add 1 (Method)</button>
230
- <button onClick={() => call('INCREMENT', 5)}>Add 5 (Command)</button>
231
- <button onClick={() => service.reset()}>Reset (Method)</button>
232
- <button onClick={() => emit('RESET')}>Reset (Event)</button>
233
- </div>
234
- );
155
+ // Per-service seed each service gets its own seed value:
156
+ @Injectable()
157
+ export class OtherService {
158
+ public constructor(@Inject(WireScope) scope: WireScope) {
159
+ const { count } = scope.getSeed(OtherService) as { count: number };
160
+ }
235
161
  }
236
162
  ```
237
163
 
238
- ## Advanced Usage
239
-
240
- ### Seeding Shared Initial State
164
+ Seeds are applied via `applySeeds` / `applySharedSeed` and removed via `unapplySeeds`.
165
+ In React, pass them as `seed` or `seeds` props to the provider — see `@wirestate/react`.
241
166
 
242
- `wirestate` supports providing initial data (seeds) to services during activation.
167
+ ## Lifecycle
243
168
 
244
- ```tsx
245
- const MainProvider = createInjectablesProvider([CounterService]);
246
-
247
- <IocProvider>
248
- <MainProvider seed={{ initialCount: 100 }}>
249
- <CounterView />
250
- </MainProvider>
251
- </IocProvider>
252
- ```
169
+ ```ts
170
+ import { OnActivated, OnDeactivation } from "@wirestate/core";
253
171
 
254
- In the service:
172
+ @Injectable()
173
+ export class PollingService {
174
+ private timer?: ReturnType<typeof setInterval>;
255
175
 
256
- ```typescript
257
- import { Injectable, Inject, SEED } from 'wirestate';
176
+ @OnActivated()
177
+ public onActivated(): void {
178
+ this.timer = setInterval(() => console.info("interval execution"), 5000);
179
+ }
258
180
 
259
- @Injectable()
260
- export class CounterService {
261
- // ...
262
- public constructor(
263
- @Inject(SEED)
264
- initialState: { initialCount: number }
265
- ) {
266
- this.count = seed.initialCount;
181
+ @OnDeactivation()
182
+ public onDeactivation(): void {
183
+ clearInterval(this.timer);
267
184
  }
268
185
  }
269
186
  ```
270
187
 
271
- ### Seeding Bound Initial State
188
+ `@OnActivated` runs after the service is bound and all dependencies are resolved.
189
+ `@OnDeactivation` runs when the container scope is disposed.
190
+
191
+ ## WireScope API
192
+
193
+ `WireScope` is injected per-service and exposes:
194
+
195
+ | Method | Description |
196
+ | ----------------------------------------- | --------------------------------------------------------------- |
197
+ | `getContainer()` | Access the raw IoC container |
198
+ | `resolve(token)` | Resolve a service or value by token |
199
+ | `resolveOptional(token)` | Resolve a service or value, returns `null` if not bound |
200
+ | `getSeed(token?)` | Get the per-service or shared seed |
201
+ | `emitEvent(type, payload?, from?)` | Emit an event |
202
+ | `subscribeToEvent(handler)` | Subscribe a handler to all events; returns unsubscribe function |
203
+ | `unsubscribeFromEvent(handler)` | Remove a specific event subscription by handler reference |
204
+ | `queryData(type, data?)` | Dispatch a query and return the result |
205
+ | `queryOptionalData(type, data?)` | Dispatch a query; returns `null` if no handler is registered |
206
+ | `registerQueryHandler(type, handler)` | Register a query handler; returns unregister function |
207
+ | `unregisterQueryHandler(type, handler)` | Remove a specific query handler by type and reference |
208
+ | `executeCommand(type, data?)` | Dispatch a command and return a descriptor |
209
+ | `executeOptionalCommand(type, data?)` | Dispatch a command; returns `null` if no handler is registered |
210
+ | `registerCommandHandler(type, handler)` | Register a command handler; returns unregister function |
211
+ | `unregisterCommandHandler(type, handler)` | Remove a specific command handler by type and reference |
212
+
213
+ ## Test utilities
214
+
215
+ Available via `@wirestate/core/test-utils`:
216
+
217
+ ```ts
218
+ import {
219
+ mockContainer,
220
+ mockService,
221
+ mockBindService,
222
+ mockBindEntry,
223
+ mockUnbindService,
224
+ } from "@wirestate/core/test-utils";
225
+ ```
226
+
227
+ ### `mockContainer(options?)`
272
228
 
273
- `wirestate` supports providing initial data (seeds) to services during activation.
229
+ Creates a configured IoC container for testing. Accepts an optional object:
274
230
 
275
- ```tsx
276
- const MainProvider = createInjectablesProvider([CounterService]);
231
+ | Option | Type | Description |
232
+ | --------------- | ---------------------------------------- | --------------------------------------------- |
233
+ | `entries` | `Array<Newable \| InjectableDescriptor>` | Services or descriptors to bind |
234
+ | `activate` | `Array<ServiceIdentifier>` | Tokens to resolve immediately after binding |
235
+ | `skipLifecycle` | `boolean` | Skip `@OnActivated` / `@OnDeactivation` hooks |
277
236
 
278
- <IocProvider>
279
- <MainProvider seeds={[[CounterService, { count: 10 }]]}>
280
- <CounterView />
281
- </MainProvider>
282
- </IocProvider>
237
+ ```ts
238
+ const container = mockContainer({
239
+ entries: [CounterService, LoggerService],
240
+ activate: [CounterService],
241
+ });
283
242
  ```
284
243
 
285
- In the service:
244
+ ### `mockService(ServiceClass, container?, options?)`
286
245
 
287
- ```typescript
288
- import { Injectable, Inject, WireScope } from 'wirestate';
246
+ Binds a service class to a container and returns its instance. Creates a new `mockContainer` if none is provided.
289
247
 
290
- @Injectable()
291
- export class CounterService {
292
- // ...
293
- public constructor(@Inject(WireScope) scope: WireScope) {
294
- this.count = scope.getSeed(CounterService).count;
295
- }
296
- }
248
+ ```ts
249
+ const counter = mockService(CounterService);
250
+ counter.increment();
251
+ expect(counter.count).toBe(1);
297
252
  ```
298
253
 
299
- ### Service Lifecycle
254
+ ### `mockBindService(container, ServiceClass, options?)`
300
255
 
301
- Use decorators to handle initialization and cleanup.
256
+ Binds a service class to an existing container. Accepts `{ skipLifecycle?: boolean }`.
302
257
 
303
- ```typescript
304
- import { OnActivated, OnDeactivation } from 'wirestate';
258
+ ### `mockBindEntry(container, entry, options?)`
305
259
 
306
- @OnActivated()
307
- public onActivated(): void {
308
- // Start polling, fetch initial data, etc.
309
- }
260
+ Binds a service class or `InjectableDescriptor` to an existing container. Accepts `{ skipLifecycle?: boolean }`.
310
261
 
311
- @OnDeactivation()
312
- public onDeactivation(): void {
313
- // Cleanup subscriptions
314
- }
262
+ ### `mockUnbindService(container, ServiceClass)`
263
+
264
+ Removes a service binding from the container. Useful for overriding registrations between tests.
265
+
266
+ ```ts
267
+ mockUnbindService(container, CounterService);
268
+ mockBindEntry(container, { token: CounterService, useValue: fakeCounter });
315
269
  ```
316
270
 
317
271
  ## License