@thi.ng/system 2.3.0 → 3.0.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.
- package/CHANGELOG.md +12 -1
- package/README.md +29 -16
- package/api.d.ts +10 -2
- package/package.json +4 -4
- package/system.d.ts +10 -3
- package/system.js +16 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2024-
|
|
3
|
+
- **Last updated**: 2024-02-06T23:18:11Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -9,6 +9,17 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
# [3.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/system@3.0.0) (2024-02-01)
|
|
13
|
+
|
|
14
|
+
#### 🛑 Breaking changes
|
|
15
|
+
|
|
16
|
+
- Async component factories ([998409d](https://github.com/thi-ng/umbrella/commit/998409d))
|
|
17
|
+
- BREAKING CHANGE: Component factory functions are async now
|
|
18
|
+
- add async System.init()
|
|
19
|
+
- update System ctor
|
|
20
|
+
- add/update docs
|
|
21
|
+
- update tests
|
|
22
|
+
|
|
12
23
|
## [2.3.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/system@2.3.0) (2024-01-31)
|
|
13
24
|
|
|
14
25
|
#### 🚀 Features
|
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
- [Status](#status)
|
|
20
20
|
- [Installation](#installation)
|
|
21
21
|
- [Dependencies](#dependencies)
|
|
22
|
+
- [Usage examples](#usage-examples)
|
|
22
23
|
- [API](#api)
|
|
23
24
|
- [Example system](#example-system)
|
|
24
25
|
- [System visualization](#system-visualization)
|
|
@@ -62,7 +63,7 @@ For Node.js REPL:
|
|
|
62
63
|
const system = await import("@thi.ng/system");
|
|
63
64
|
```
|
|
64
65
|
|
|
65
|
-
Package sizes (brotli'd, pre-treeshake): ESM:
|
|
66
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 570 bytes
|
|
66
67
|
|
|
67
68
|
## Dependencies
|
|
68
69
|
|
|
@@ -70,6 +71,16 @@ Package sizes (brotli'd, pre-treeshake): ESM: 539 bytes
|
|
|
70
71
|
- [@thi.ng/dgraph](https://github.com/thi-ng/umbrella/tree/develop/packages/dgraph)
|
|
71
72
|
- [@thi.ng/logger](https://github.com/thi-ng/umbrella/tree/develop/packages/logger)
|
|
72
73
|
|
|
74
|
+
## Usage examples
|
|
75
|
+
|
|
76
|
+
One project in this repo's
|
|
77
|
+
[/examples](https://github.com/thi-ng/umbrella/tree/develop/examples)
|
|
78
|
+
directory is using this package:
|
|
79
|
+
|
|
80
|
+
| Screenshot | Description | Live demo | Source |
|
|
81
|
+
|:--------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------|:---------------------------------------------------------|:--------------------------------------------------------------------------------------|
|
|
82
|
+
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rstream-system-bus.png" width="240"/> | Declarative component-based system with central rstream-based pubsub event bus | [Demo](https://demo.thi.ng/umbrella/rstream-system-bus/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rstream-system-bus) |
|
|
83
|
+
|
|
73
84
|
## API
|
|
74
85
|
|
|
75
86
|
[Generated API docs](https://docs.thi.ng/umbrella/system/)
|
|
@@ -78,7 +89,7 @@ TODO
|
|
|
78
89
|
|
|
79
90
|
### Example system
|
|
80
91
|
|
|
81
|
-
```ts
|
|
92
|
+
```ts tangle:export/readme.ts
|
|
82
93
|
import { defSystem, ILifecycle } from "@thi.ng/system";
|
|
83
94
|
|
|
84
95
|
// Step 1: Define the structure / components of your system
|
|
@@ -152,16 +163,16 @@ class Cache implements ILifecycle {
|
|
|
152
163
|
|
|
153
164
|
const FOO = defSystem<FooSys>({
|
|
154
165
|
db: {
|
|
155
|
-
factory: (deps) => new DB(deps.logger, deps.
|
|
156
|
-
deps: ["logger", "
|
|
166
|
+
factory: async (deps) => new DB(deps.logger, deps.cache),
|
|
167
|
+
deps: ["logger", "cache"],
|
|
157
168
|
},
|
|
158
|
-
logger: { factory: () => new Logger() },
|
|
169
|
+
logger: { factory: async () => new Logger() },
|
|
159
170
|
cache: {
|
|
160
|
-
factory: ({ logger }) => new Cache(logger),
|
|
171
|
+
factory: async ({ logger }) => new Cache(logger),
|
|
161
172
|
deps: ["logger"],
|
|
162
173
|
},
|
|
163
174
|
dummy: {
|
|
164
|
-
factory: ({ logger }) => ({
|
|
175
|
+
factory: async ({ logger }) => ({
|
|
165
176
|
async start() {
|
|
166
177
|
logger.info("start dummy");
|
|
167
178
|
return true;
|
|
@@ -176,21 +187,21 @@ const FOO = defSystem<FooSys>({
|
|
|
176
187
|
});
|
|
177
188
|
|
|
178
189
|
// Step 4: Asynchronously start all components in dependency order
|
|
179
|
-
FOO.start();
|
|
190
|
+
await FOO.start();
|
|
180
191
|
// [info] start logger
|
|
181
192
|
// [info] start cache
|
|
182
193
|
// [info] start dummy
|
|
183
194
|
// [info] start db
|
|
184
195
|
|
|
185
196
|
// Step 5 (optional): Async shutdown all (in reverse order)
|
|
186
|
-
FOO.stop();
|
|
197
|
+
await FOO.stop();
|
|
187
198
|
// [info] stop db
|
|
188
199
|
// [info] stop dummy
|
|
189
200
|
// [info] stop cache
|
|
190
201
|
// [info] stop logger
|
|
191
202
|
|
|
192
|
-
//
|
|
193
|
-
FOO.reset();
|
|
203
|
+
// Alternatively, calls stop() & if successful followed by start()
|
|
204
|
+
await FOO.reset();
|
|
194
205
|
```
|
|
195
206
|
|
|
196
207
|
### System visualization
|
|
@@ -198,7 +209,9 @@ FOO.reset();
|
|
|
198
209
|
For a `System` to initialize its components in the correct order, an internal
|
|
199
210
|
[dependency
|
|
200
211
|
graph](https://github.com/thi-ng/umbrella/tree/develop/packages/dgraph) is
|
|
201
|
-
constructed. This graph is not required any further after system
|
|
212
|
+
constructed. This graph is not required any further after system initialization
|
|
213
|
+
(see
|
|
214
|
+
[System.init()](https://docs.thi.ng/umbrella/system/classes/System.html#init)),
|
|
202
215
|
though can be useful for debugging and documentation purposes.
|
|
203
216
|
|
|
204
217
|
For example, we can utilize the
|
|
@@ -206,18 +219,18 @@ For example, we can utilize the
|
|
|
206
219
|
package to generate a [Graphviz](https://graphviz.org) source file to visualize
|
|
207
220
|
the dependencies between the system's components.
|
|
208
221
|
|
|
209
|
-
```ts
|
|
222
|
+
```ts tangle:export/readme.ts
|
|
210
223
|
import { toDot } from "@thi.ng/dgraph-dot";
|
|
211
224
|
|
|
212
225
|
console.log(toDot(FOO.graph, { id: (node) => node }));
|
|
213
226
|
// digraph g {
|
|
214
227
|
// "db"[label="db"];
|
|
215
228
|
// "logger"[label="logger"];
|
|
216
|
-
// "
|
|
229
|
+
// "cache"[label="cache"];
|
|
217
230
|
// "dummy"[label="dummy"];
|
|
218
231
|
// "db" -> "logger";
|
|
219
|
-
// "db" -> "
|
|
220
|
-
// "
|
|
232
|
+
// "db" -> "cache";
|
|
233
|
+
// "cache" -> "logger";
|
|
221
234
|
// "dummy" -> "logger";
|
|
222
235
|
// }
|
|
223
236
|
```
|
package/api.d.ts
CHANGED
|
@@ -33,11 +33,19 @@ export interface ILifecycle<T extends SystemMap<T> = any> {
|
|
|
33
33
|
*/
|
|
34
34
|
export type SystemMap<T> = Record<Keys<T>, ILifecycle>;
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* Async system component initialization function.
|
|
37
37
|
*/
|
|
38
|
-
export type ComponentFactory<T extends SystemMap<T>> = Fn<T, ILifecycle
|
|
38
|
+
export type ComponentFactory<T extends SystemMap<T>> = Fn<T, Promise<ILifecycle>>;
|
|
39
39
|
export interface SystemSpec<T extends SystemMap<T>> {
|
|
40
|
+
/**
|
|
41
|
+
* Async system component initialization function.
|
|
42
|
+
*/
|
|
40
43
|
factory: ComponentFactory<T>;
|
|
44
|
+
/**
|
|
45
|
+
* Component IDs which this component directly depends on. Used to construct
|
|
46
|
+
* the system's dependency graph and to initialize (and later start)
|
|
47
|
+
* components in the correct order.
|
|
48
|
+
*/
|
|
41
49
|
deps?: Keys<T>[];
|
|
42
50
|
}
|
|
43
51
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/system",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Minimal and explicit dependency-injection & lifecycle container for stateful app components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@thi.ng/api": "^8.9.22",
|
|
42
|
-
"@thi.ng/dgraph": "^2.1.
|
|
43
|
-
"@thi.ng/logger": "^2.1.
|
|
42
|
+
"@thi.ng/dgraph": "^2.1.94",
|
|
43
|
+
"@thi.ng/logger": "^2.1.9"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@microsoft/api-extractor": "^7.39.0",
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"thi.ng": {
|
|
85
85
|
"year": 2020
|
|
86
86
|
},
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "ce8202c237a367c4038d41919a8acf75e1122507\n"
|
|
88
88
|
}
|
package/system.d.ts
CHANGED
|
@@ -4,14 +4,21 @@ import { type ILifecycle, type SystemMap, type SystemSpecs } from "./api.js";
|
|
|
4
4
|
/**
|
|
5
5
|
* Syntax sugar for {@link System} constructor.
|
|
6
6
|
*
|
|
7
|
-
* @param
|
|
7
|
+
* @param specs
|
|
8
8
|
*/
|
|
9
|
-
export declare const defSystem: <T extends SystemMap<T>>(
|
|
9
|
+
export declare const defSystem: <T extends SystemMap<T>>(specs: SystemSpecs<T>) => System<T>;
|
|
10
10
|
export declare class System<T extends SystemMap<T>> implements ILifecycle<T> {
|
|
11
|
+
protected specs: SystemSpecs<T>;
|
|
11
12
|
components: T;
|
|
12
13
|
topology: Keys<T>[];
|
|
13
14
|
graph: DGraph<Keys<T>>;
|
|
14
|
-
constructor(
|
|
15
|
+
constructor(specs: SystemSpecs<T>);
|
|
16
|
+
/**
|
|
17
|
+
* Builds the system component dependency graph and initializes all
|
|
18
|
+
* components using their async {@link SystemSpec.factory} functions.
|
|
19
|
+
* Returns the initialized system.
|
|
20
|
+
*/
|
|
21
|
+
init(): Promise<this>;
|
|
15
22
|
/**
|
|
16
23
|
* Initializes all system components in dependency order. If any component's
|
|
17
24
|
* `start()` method returns false, system start up will be stopped, any
|
package/system.js
CHANGED
|
@@ -2,22 +2,31 @@ import { DGraph } from "@thi.ng/dgraph";
|
|
|
2
2
|
import {
|
|
3
3
|
LOGGER
|
|
4
4
|
} from "./api.js";
|
|
5
|
-
const defSystem = (
|
|
5
|
+
const defSystem = (specs) => new System(specs);
|
|
6
6
|
class System {
|
|
7
|
+
constructor(specs) {
|
|
8
|
+
this.specs = specs;
|
|
9
|
+
}
|
|
7
10
|
components;
|
|
8
11
|
topology;
|
|
9
12
|
graph;
|
|
10
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Builds the system component dependency graph and initializes all
|
|
15
|
+
* components using their async {@link SystemSpec.factory} functions.
|
|
16
|
+
* Returns the initialized system.
|
|
17
|
+
*/
|
|
18
|
+
async init() {
|
|
11
19
|
this.graph = new DGraph();
|
|
12
|
-
for (let id in
|
|
13
|
-
const deps =
|
|
20
|
+
for (let id in this.specs) {
|
|
21
|
+
const deps = this.specs[id].deps;
|
|
14
22
|
deps ? this.graph.addDependencies(id, deps) : this.graph.addNode(id);
|
|
15
23
|
}
|
|
16
24
|
this.topology = this.graph.sort();
|
|
17
25
|
this.components = {};
|
|
18
26
|
for (let id of this.topology) {
|
|
19
|
-
this.components[id] =
|
|
27
|
+
this.components[id] = await this.specs[id].factory(this.components);
|
|
20
28
|
}
|
|
29
|
+
return this;
|
|
21
30
|
}
|
|
22
31
|
/**
|
|
23
32
|
* Initializes all system components in dependency order. If any component's
|
|
@@ -30,6 +39,8 @@ class System {
|
|
|
30
39
|
* **not** be intercepted.
|
|
31
40
|
*/
|
|
32
41
|
async start() {
|
|
42
|
+
if (!this.graph)
|
|
43
|
+
await this.init();
|
|
33
44
|
const topo = this.topology;
|
|
34
45
|
for (let i = 0; i < topo.length; i++) {
|
|
35
46
|
const id = topo[i];
|