@syncbridge/common 1.1.4 → 2.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/README.md +192 -1
- package/app-factory.d.ts +29 -0
- package/{processor-factory.js → app-factory.js} +63 -44
- package/classes/{processor-base.d.ts → app-base.d.ts} +3 -3
- package/classes/app-base.js +10 -0
- package/classes/base-element.d.ts +3 -0
- package/classes/base-element.js +2 -1
- package/classes/component-base.d.ts +6 -6
- package/classes/component-base.js +2 -3
- package/classes/console-logger.js +0 -1
- package/classes/frame-stream.js +0 -1
- package/classes/log-channel-writer.d.ts +32 -0
- package/classes/log-channel-writer.js +96 -0
- package/classes/runnable.d.ts +6 -0
- package/classes/runnable.js +22 -1
- package/classes/sb-error.js +0 -1
- package/classes/stack-executor.js +0 -1
- package/constants.d.ts +1 -1
- package/constants.js +1 -2
- package/decorators/app-events.decorator.d.ts +5 -0
- package/decorators/{processor-events.decorator.js → app-events.decorator.js} +0 -1
- package/decorators/app.decorator.d.ts +29 -0
- package/decorators/{processor.decorator.js → app.decorator.js} +24 -19
- package/decorators/component.decorator.js +13 -6
- package/decorators/decorator-helpers.js +0 -1
- package/decorators/define-variable.decorator.d.ts +6 -1
- package/decorators/define-variable.decorator.js +5 -2
- package/decorators/log-channel.decorator.d.ts +97 -0
- package/decorators/log-channel.decorator.js +33 -0
- package/decorators/use-component.decorator.d.ts +2 -2
- package/decorators/use-component.decorator.js +1 -2
- package/decorators/use-variables.decorator.d.ts +2 -2
- package/decorators/use-variables.decorator.js +0 -1
- package/host-link/host-identity.d.ts +53 -0
- package/host-link/host-identity.js +139 -0
- package/host-link/host-link.d.ts +43 -0
- package/host-link/host-link.js +53 -0
- package/host-link/host-packages.d.ts +25 -0
- package/host-link/host-packages.js +9 -0
- package/host-link/host-workers.d.ts +75 -0
- package/host-link/host-workers.js +28 -0
- package/host-link/multiplexer.d.ts +115 -0
- package/host-link/multiplexer.js +288 -0
- package/host-link/sealed-box.d.ts +21 -0
- package/host-link/sealed-box.js +103 -0
- package/index.d.ts +16 -3
- package/index.js +16 -4
- package/interfaces/index.js +0 -1
- package/interfaces/logger.interface.js +0 -1
- package/models/enums/enum-source.enum.d.ts +11 -0
- package/models/enums/enum-source.enum.js +21 -0
- package/models/enums/log-channel-kind.d.ts +7 -0
- package/models/enums/log-channel-kind.js +13 -0
- package/models/enums/log-level.js +0 -1
- package/models/enums/service-status.d.ts +5 -1
- package/models/enums/service-status.js +4 -1
- package/models/enums/variable-format.enum.js +0 -1
- package/models/enums/variable-type.enum.js +0 -1
- package/models/enums/worker-permission.enum.d.ts +16 -0
- package/models/enums/worker-permission.enum.js +27 -0
- package/models/index.d.ts +6 -1
- package/models/index.js +6 -2
- package/models/metadata/app-metadata.d.ts +6 -0
- package/models/metadata/{processor-metadata.js → app-metadata.js} +6 -7
- package/models/metadata/component-metadata.js +0 -1
- package/models/metadata/element-component-metadata.d.ts +2 -0
- package/models/metadata/element-component-metadata.js +10 -3
- package/models/metadata/element-metadata.d.ts +8 -0
- package/models/metadata/element-metadata.js +40 -1
- package/models/metadata/log-channel-metadata.d.ts +23 -0
- package/models/metadata/log-channel-metadata.js +72 -0
- package/models/metadata/package-metadata.js +0 -1
- package/models/metadata/plugin-metadata.d.ts +15 -0
- package/models/metadata/plugin-metadata.js +65 -0
- package/models/metadata/variable-metadata.d.ts +3 -0
- package/models/metadata/variable-metadata.js +15 -2
- package/models/profile/log-options.d.ts +17 -0
- package/models/profile/log-options.js +58 -2
- package/models/profile/profile-component.js +0 -1
- package/models/profile/profile.d.ts +2 -2
- package/models/profile/profile.js +9 -10
- package/models-document.js +0 -1
- package/package.json +6 -2
- package/registry/docs-sidebar.d.ts +59 -0
- package/registry/docs-sidebar.js +169 -0
- package/registry/extension-package.d.ts +40 -13
- package/registry/extension-package.js +59 -19
- package/registry/extension-registry.d.ts +16 -16
- package/registry/extension-registry.js +59 -45
- package/registry/module-catalog.d.ts +31 -0
- package/registry/module-catalog.js +88 -0
- package/registry/package-docs.d.ts +98 -0
- package/registry/package-docs.js +159 -0
- package/registry/package-manifest.d.ts +54 -3
- package/registry/package-manifest.js +59 -2
- package/utils/decode-profile.d.ts +18 -2
- package/utils/decode-profile.js +65 -10
- package/utils/encrypt-helpers.d.ts +7 -0
- package/utils/encrypt-helpers.js +12 -6
- package/utils/locate-package-json.js +0 -1
- package/utils/materialize-metadata.d.ts +3 -3
- package/utils/materialize-metadata.js +16 -13
- package/utils/normalize-metadata.d.ts +23 -4
- package/utils/normalize-metadata.js +52 -7
- package/utils/registry-names.js +0 -1
- package/utils/resolve-promises.js +0 -1
- package/utils/type-guards.d.ts +2 -2
- package/utils/type-guards.js +4 -5
- package/utils/uri-to-id.js +0 -1
- package/utils/worker-permissions.d.ts +25 -0
- package/utils/worker-permissions.js +59 -0
- package/classes/base-element.js.map +0 -1
- package/classes/component-base.js.map +0 -1
- package/classes/console-logger.js.map +0 -1
- package/classes/frame-stream.js.map +0 -1
- package/classes/processor-base.js +0 -11
- package/classes/processor-base.js.map +0 -1
- package/classes/runnable.js.map +0 -1
- package/classes/sb-error.js.map +0 -1
- package/classes/stack-executor.js.map +0 -1
- package/constants.js.map +0 -1
- package/decorators/component.decorator.js.map +0 -1
- package/decorators/decorator-helpers.js.map +0 -1
- package/decorators/define-variable.decorator.js.map +0 -1
- package/decorators/processor-events.decorator.d.ts +0 -5
- package/decorators/processor-events.decorator.js.map +0 -1
- package/decorators/processor.decorator.d.ts +0 -29
- package/decorators/processor.decorator.js.map +0 -1
- package/decorators/use-component.decorator.js.map +0 -1
- package/decorators/use-variables.decorator.js.map +0 -1
- package/index.js.map +0 -1
- package/interfaces/index.js.map +0 -1
- package/interfaces/logger.interface.js.map +0 -1
- package/models/enums/log-level.js.map +0 -1
- package/models/enums/service-status.js.map +0 -1
- package/models/enums/variable-format.enum.js.map +0 -1
- package/models/enums/variable-type.enum.js.map +0 -1
- package/models/index.js.map +0 -1
- package/models/metadata/component-metadata.js.map +0 -1
- package/models/metadata/element-component-metadata.js.map +0 -1
- package/models/metadata/element-metadata.js.map +0 -1
- package/models/metadata/package-metadata.js.map +0 -1
- package/models/metadata/processor-metadata.d.ts +0 -6
- package/models/metadata/processor-metadata.js.map +0 -1
- package/models/metadata/variable-metadata.js.map +0 -1
- package/models/profile/log-options.js.map +0 -1
- package/models/profile/profile-component.js.map +0 -1
- package/models/profile/profile.js.map +0 -1
- package/models-document.js.map +0 -1
- package/processor-factory.d.ts +0 -26
- package/processor-factory.js.map +0 -1
- package/registry/extension-package.js.map +0 -1
- package/registry/extension-registry.js.map +0 -1
- package/registry/package-manifest.js.map +0 -1
- package/utils/decode-profile.js.map +0 -1
- package/utils/encrypt-helpers.js.map +0 -1
- package/utils/locate-package-json.js.map +0 -1
- package/utils/materialize-metadata.js.map +0 -1
- package/utils/normalize-metadata.js.map +0 -1
- package/utils/registry-names.js.map +0 -1
- package/utils/resolve-promises.js.map +0 -1
- package/utils/type-guards.js.map +0 -1
- package/utils/uri-to-id.js.map +0 -1
package/README.md
CHANGED
|
@@ -1 +1,192 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @syncbridge/common
|
|
2
|
+
|
|
3
|
+
What a SyncBridge module is written against. A module is an npm package
|
|
4
|
+
of **components** - clients, servers, connections - and **apps**, which
|
|
5
|
+
SyncBridge runs as workers, each a Node.js process of its own, made of
|
|
6
|
+
components. This package gives you the decorators that describe them, the
|
|
7
|
+
base classes they extend, and their lifecycle.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm i -D @syncbridge/common
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
SyncBridge provides `@syncbridge/common` to every module it runs, so a
|
|
14
|
+
module declares it in `peerDependencies`, never in `dependencies`:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
"peerDependencies": { "@syncbridge/common": "^2.0.0" }
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Start a module with `npx @syncbridge/syncbuild init @vendor/name`
|
|
21
|
+
([`@syncbridge/syncbuild`](https://www.npmjs.com/package/@syncbridge/syncbuild)),
|
|
22
|
+
and test it with
|
|
23
|
+
[`@syncbridge/testing`](https://www.npmjs.com/package/@syncbridge/testing).
|
|
24
|
+
|
|
25
|
+
## A component
|
|
26
|
+
|
|
27
|
+
A component is a class that extends `ComponentBase`, decorated with
|
|
28
|
+
`@Component`. Its settings - shown in SyncBridge's UI and kept in the
|
|
29
|
+
worker's profile - are a variables class, given with `UseVariables`:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import {
|
|
33
|
+
Component,
|
|
34
|
+
ComponentBase,
|
|
35
|
+
DefineVariable,
|
|
36
|
+
VariableType,
|
|
37
|
+
} from '@syncbridge/common';
|
|
38
|
+
|
|
39
|
+
export class WeatherClientVariables {
|
|
40
|
+
@DefineVariable({ label: 'API address', required: true })
|
|
41
|
+
declare url: string;
|
|
42
|
+
|
|
43
|
+
@DefineVariable({ label: 'API key', type: VariableType.Secret })
|
|
44
|
+
declare apiKey?: string;
|
|
45
|
+
|
|
46
|
+
@DefineVariable({ label: 'Interval (s)', default: 60, minValue: 5 })
|
|
47
|
+
declare interval: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@Component({
|
|
51
|
+
displayName: 'Weather client',
|
|
52
|
+
description: 'Reads the weather from a web service',
|
|
53
|
+
tags: ['weather', 'http'],
|
|
54
|
+
})
|
|
55
|
+
export class WeatherClientComponent extends ComponentBase {
|
|
56
|
+
@Component.UseVariables()
|
|
57
|
+
declare values: WeatherClientVariables;
|
|
58
|
+
|
|
59
|
+
protected async _start(abortSignal?: AbortSignal): Promise<void> {
|
|
60
|
+
await super._start(abortSignal);
|
|
61
|
+
this.logger?.info(`Reading ${this.values.url}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected async _stop(): Promise<void> {
|
|
65
|
+
/* Close what _start opened */
|
|
66
|
+
await super._stop();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
An element's URI is `<package>:<className>`. A component's class name is
|
|
72
|
+
its class's without `Component` (`@acme/weather:WeatherClient`); an app's
|
|
73
|
+
is its class's (`@acme/weather:WeatherStationApp`). Give `className` to
|
|
74
|
+
choose another.
|
|
75
|
+
|
|
76
|
+
## An app
|
|
77
|
+
|
|
78
|
+
An app extends `AppBase`, decorated with `@App`. It names the components it
|
|
79
|
+
uses with `UseComponent`, by URI. SyncBridge creates them with the values the
|
|
80
|
+
worker's profile gives, and starts them before the app:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { App, AppBase, DefineVariable } from '@syncbridge/common';
|
|
84
|
+
import type { WeatherClientComponent } from './weather-client.component.js';
|
|
85
|
+
|
|
86
|
+
export class WeatherStationVariables {
|
|
87
|
+
@DefineVariable({ label: 'Station name', default: 'Station 1' })
|
|
88
|
+
declare name: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@App({ displayName: 'Weather station' })
|
|
92
|
+
export class WeatherStationApp extends AppBase {
|
|
93
|
+
@App.UseVariables()
|
|
94
|
+
declare values: WeatherStationVariables;
|
|
95
|
+
|
|
96
|
+
@App.UseComponent({
|
|
97
|
+
uri: '@acme/weather:WeatherClient',
|
|
98
|
+
required: true,
|
|
99
|
+
})
|
|
100
|
+
declare readonly weather: WeatherClientComponent;
|
|
101
|
+
|
|
102
|
+
protected async _start(abortSignal?: AbortSignal): Promise<void> {
|
|
103
|
+
await super._start(abortSignal);
|
|
104
|
+
this.logger?.info(`${this.values.name} started`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
A component may use components too, with `Component.UseComponent`. A URI
|
|
110
|
+
can name another module's component, for example
|
|
111
|
+
`@syncbridge/net:TcpClient`. Declare that module as a peer as well.
|
|
112
|
+
|
|
113
|
+
## Variables
|
|
114
|
+
|
|
115
|
+
`@DefineVariable` describes a setting. Its type is read from the
|
|
116
|
+
property's TypeScript type when not given. Some options:
|
|
117
|
+
|
|
118
|
+
| Option | Meaning |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| `label`, `description` | How it is shown |
|
|
121
|
+
| `type` | `VariableType`: `String`, `Secret` (a password or key, kept encrypted in the profile), `Number`, `BigInt`, `Boolean`, `Enum`, `Nested` |
|
|
122
|
+
| `default`, `required` | Its default value, and whether it must be given |
|
|
123
|
+
| `enumValues` | The values of an enum |
|
|
124
|
+
| `enumSource` | Values SyncBridge fills in from the server it runs on: `EnumSource.SerialPorts`, `EnumSource.NetworkAddresses` |
|
|
125
|
+
| `format`, `pattern` | A string's format (`url`, `email`, `date-time`...) or pattern |
|
|
126
|
+
| `minValue`, `maxValue` | A number's range |
|
|
127
|
+
| `isArray` | A list of values |
|
|
128
|
+
| `hotPlug` | A change applies while running, without a restart |
|
|
129
|
+
| `index` | Its order in the UI |
|
|
130
|
+
|
|
131
|
+
## Lifecycle
|
|
132
|
+
|
|
133
|
+
Apps and components are `Runnable`s. Override the protected methods, and
|
|
134
|
+
always call `super`:
|
|
135
|
+
|
|
136
|
+
- `_init()`: once, before the first start.
|
|
137
|
+
- `_start(abortSignal)`: start working. The signal aborts when a stop comes
|
|
138
|
+
while starting.
|
|
139
|
+
- `_stop()`: stop, and release what `_start` took. Close every timer,
|
|
140
|
+
socket and pool: what is left open is logged as a warning when the
|
|
141
|
+
worker ends.
|
|
142
|
+
- `_restart()`: stop and start in place, for example when values change.
|
|
143
|
+
|
|
144
|
+
`status` is a `ServiceStatus`: `stopped`, `starting`, `started`,
|
|
145
|
+
`unhealthy`, `stopping`. Report trouble with
|
|
146
|
+
`this.setStatus(ServiceStatus.unhealthy, message)`. An app's status
|
|
147
|
+
follows its components'.
|
|
148
|
+
|
|
149
|
+
## Logging
|
|
150
|
+
|
|
151
|
+
`this.logger` writes the element's log. A log channel is a log of its own
|
|
152
|
+
that the user can turn on, filter and keep apart, such as what a
|
|
153
|
+
connection sends and receives:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import { LogChannel } from '@syncbridge/common';
|
|
157
|
+
|
|
158
|
+
@LogChannel({ name: 'communication', title: 'Communication', kind: 'transmit' })
|
|
159
|
+
declare readonly ioLog: LogChannel;
|
|
160
|
+
|
|
161
|
+
// later
|
|
162
|
+
this.ioLog.info('Sent', { bytes: 42 });
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Permissions
|
|
166
|
+
|
|
167
|
+
SyncBridge runs each worker as a Linux user of its own, under Node's
|
|
168
|
+
permission model. A component or app that needs more than its own data
|
|
169
|
+
directory declares it:
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
@Component({
|
|
173
|
+
displayName: 'Serial client',
|
|
174
|
+
permissions: [WorkerPermission.SerialPorts, WorkerPermission.NativeCode],
|
|
175
|
+
})
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
- `SerialPorts`: the serial devices.
|
|
179
|
+
- `NativeCode`: native addons (`.node`), such as `serialport` or `oracledb`.
|
|
180
|
+
- `ChildProcesses`: starting other programs.
|
|
181
|
+
|
|
182
|
+
A subclass has its base's permissions. `spm verify` runs a module under
|
|
183
|
+
the permission model and tells you what it failed to declare.
|
|
184
|
+
|
|
185
|
+
## Examples
|
|
186
|
+
|
|
187
|
+
The modules SyncBridge ships are open source:
|
|
188
|
+
[syncbridge-io/public-modules](https://github.com/syncbridge-io/public-modules).
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
[MIT](LICENSE)
|
package/app-factory.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { AppBase } from './classes/app-base.js';
|
|
2
|
+
import { StackExecutor } from './classes/stack-executor.js';
|
|
3
|
+
import type { LogChannel } from './decorators/log-channel.decorator.js';
|
|
4
|
+
import type { ILogger } from './interfaces/index.js';
|
|
5
|
+
import { Profile } from './models/index.js';
|
|
6
|
+
export declare namespace AppFactory {
|
|
7
|
+
const METADATA_KEY: unique symbol;
|
|
8
|
+
const PROFILE_KEY: unique symbol;
|
|
9
|
+
interface AppOptions {
|
|
10
|
+
logger?: ILogger;
|
|
11
|
+
dataDirectory?: string;
|
|
12
|
+
/** Where the log channels hand their records; without it they drop them */
|
|
13
|
+
logSink?: LogChannel.Sink;
|
|
14
|
+
}
|
|
15
|
+
function createApp<T extends AppBase>(profile: Profile, options?: AppOptions): Promise<T>;
|
|
16
|
+
function createAppSilent<T extends AppBase>(profile: Profile, options?: AppOptions): Promise<{
|
|
17
|
+
result: true;
|
|
18
|
+
app: T;
|
|
19
|
+
issues: StackExecutor.Issue[];
|
|
20
|
+
} | {
|
|
21
|
+
result: false;
|
|
22
|
+
issues: StackExecutor.Issue[];
|
|
23
|
+
}>;
|
|
24
|
+
function updateApp(app: AppBase, profile: Profile, options?: AppOptions): Promise<void>;
|
|
25
|
+
function updateAppSilent(app: AppBase, profile: Profile, options?: AppOptions): Promise<{
|
|
26
|
+
result: boolean;
|
|
27
|
+
issues: StackExecutor.Issue[];
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { clone } from '@jsopen/objects';
|
|
2
2
|
import equal from 'fast-deep-equal';
|
|
3
|
+
import { AppBase } from './classes/app-base.js';
|
|
3
4
|
import { ComponentBase } from './classes/component-base.js';
|
|
4
|
-
import {
|
|
5
|
+
import { LogChannelWriter } from './classes/log-channel-writer.js';
|
|
5
6
|
import { SbError, SbValidationError } from './classes/sb-error.js';
|
|
6
7
|
import { StackExecutor } from './classes/stack-executor.js';
|
|
7
|
-
import {
|
|
8
|
+
import { AppMetadata, ElementComponentMetadataRecord, Profile, ProfileComponentRecord, VariableMetadataRecord, } from './models/index.js';
|
|
8
9
|
import { initializeModelsDocument } from './models-document.js';
|
|
9
10
|
import { ExtensionRegistry } from './registry/extension-registry.js';
|
|
10
11
|
import { decodeProfileSilent } from './utils/decode-profile.js';
|
|
11
|
-
export var
|
|
12
|
-
(function (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
async function
|
|
16
|
-
const r1 = await
|
|
12
|
+
export var AppFactory;
|
|
13
|
+
(function (AppFactory) {
|
|
14
|
+
AppFactory.METADATA_KEY = Symbol('METADATA');
|
|
15
|
+
AppFactory.PROFILE_KEY = Symbol('PROFILE');
|
|
16
|
+
async function createApp(profile, options) {
|
|
17
|
+
const r1 = await createAppSilent(profile, options);
|
|
17
18
|
if (!r1.result) {
|
|
18
|
-
const msg = 'Error while creating
|
|
19
|
+
const msg = 'Error while creating app.\n ' +
|
|
19
20
|
r1.issues
|
|
20
21
|
.map(issue => `- ${issue.message}. Location: /${issue.location}`)
|
|
21
22
|
.join('\n ');
|
|
@@ -27,19 +28,19 @@ export var ProcessorFactory;
|
|
|
27
28
|
issues: r1.issues,
|
|
28
29
|
});
|
|
29
30
|
}
|
|
30
|
-
return r1.
|
|
31
|
+
return r1.app;
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
-
async function
|
|
33
|
+
AppFactory.createApp = createApp;
|
|
34
|
+
async function createAppSilent(profile, options) {
|
|
34
35
|
const ctx = {
|
|
35
36
|
stackExecutor: new StackExecutor(),
|
|
36
|
-
|
|
37
|
+
app: undefined,
|
|
37
38
|
profile,
|
|
38
39
|
options,
|
|
39
40
|
};
|
|
40
41
|
try {
|
|
41
42
|
await initializeModelsDocument();
|
|
42
|
-
if (!(await
|
|
43
|
+
if (!(await _configureApp(ctx))) {
|
|
43
44
|
return {
|
|
44
45
|
result: false,
|
|
45
46
|
issues: ctx.stackExecutor.issues,
|
|
@@ -47,7 +48,7 @@ export var ProcessorFactory;
|
|
|
47
48
|
}
|
|
48
49
|
return {
|
|
49
50
|
result: true,
|
|
50
|
-
|
|
51
|
+
app: ctx.app,
|
|
51
52
|
issues: ctx.stackExecutor.issues,
|
|
52
53
|
};
|
|
53
54
|
}
|
|
@@ -66,11 +67,11 @@ export var ProcessorFactory;
|
|
|
66
67
|
};
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
-
async function
|
|
71
|
-
const r1 = await
|
|
70
|
+
AppFactory.createAppSilent = createAppSilent;
|
|
71
|
+
async function updateApp(app, profile, options) {
|
|
72
|
+
const r1 = await updateAppSilent(app, profile, options);
|
|
72
73
|
if (!r1.result) {
|
|
73
|
-
const msg = 'Error while updating
|
|
74
|
+
const msg = 'Error while updating app.\n ' +
|
|
74
75
|
r1.issues
|
|
75
76
|
.map(issue => `- ${issue.message}. Location: /${issue.location}`)
|
|
76
77
|
.join('\n ');
|
|
@@ -83,20 +84,20 @@ export var ProcessorFactory;
|
|
|
83
84
|
});
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
-
async function
|
|
87
|
+
AppFactory.updateApp = updateApp;
|
|
88
|
+
async function updateAppSilent(app, profile, options) {
|
|
88
89
|
if (options?.logger)
|
|
89
|
-
|
|
90
|
+
app.logger = options.logger;
|
|
90
91
|
if (options?.dataDirectory)
|
|
91
|
-
|
|
92
|
+
app.dataDirectory = options.dataDirectory;
|
|
92
93
|
const ctx = {
|
|
93
94
|
stackExecutor: new StackExecutor(),
|
|
94
|
-
|
|
95
|
+
app,
|
|
95
96
|
profile,
|
|
96
97
|
options,
|
|
97
98
|
valueUpdates: new Map(),
|
|
98
99
|
};
|
|
99
|
-
if (!(await
|
|
100
|
+
if (!(await _configureApp(ctx))) {
|
|
100
101
|
return {
|
|
101
102
|
result: false,
|
|
102
103
|
issues: ctx.stackExecutor.issues,
|
|
@@ -113,14 +114,14 @@ export var ProcessorFactory;
|
|
|
113
114
|
await obj.emitAsyncSafe('values-updated', properties);
|
|
114
115
|
}
|
|
115
116
|
};
|
|
116
|
-
await signalUpdates(
|
|
117
|
+
await signalUpdates(app);
|
|
117
118
|
return {
|
|
118
119
|
result: true,
|
|
119
120
|
issues: ctx.stackExecutor.issues,
|
|
120
121
|
};
|
|
121
122
|
}
|
|
122
|
-
|
|
123
|
-
async function
|
|
123
|
+
AppFactory.updateAppSilent = updateAppSilent;
|
|
124
|
+
async function _configureApp(ctx) {
|
|
124
125
|
/* Decode profile */
|
|
125
126
|
const r1 = decodeProfileSilent(ctx.profile);
|
|
126
127
|
if (!r1.result) {
|
|
@@ -128,14 +129,14 @@ export var ProcessorFactory;
|
|
|
128
129
|
return false;
|
|
129
130
|
}
|
|
130
131
|
ctx.profile = r1.profile;
|
|
131
|
-
const oldMetadata = ctx.
|
|
132
|
-
const oldProfile = ctx.
|
|
133
|
-
if (!ctx.
|
|
134
|
-
/* Create new
|
|
135
|
-
const reg = ExtensionRegistry.
|
|
136
|
-
const
|
|
137
|
-
/* Create
|
|
138
|
-
ctx.
|
|
132
|
+
const oldMetadata = ctx.app?.[AppFactory.METADATA_KEY];
|
|
133
|
+
const oldProfile = ctx.app?.[AppFactory.PROFILE_KEY];
|
|
134
|
+
if (!ctx.app) {
|
|
135
|
+
/* Create new app instance */
|
|
136
|
+
const reg = ExtensionRegistry.getApp(r1.profile.appUri, r1.profile.appVersion);
|
|
137
|
+
const appClass = await reg.getClass();
|
|
138
|
+
/* Create app instance */
|
|
139
|
+
ctx.app = new appClass({
|
|
139
140
|
name: r1.profile.displayName,
|
|
140
141
|
logger: ctx.options?.logger,
|
|
141
142
|
values: r1.profile.values ? clone(r1.profile.values) : {},
|
|
@@ -145,14 +146,14 @@ export var ProcessorFactory;
|
|
|
145
146
|
else {
|
|
146
147
|
/* Update values */
|
|
147
148
|
if (!ctx.stackExecutor.execute('values', () => {
|
|
148
|
-
_patchValues(ctx, ctx.
|
|
149
|
+
_patchValues(ctx, ctx.app, ctx.app.values, '', r1.profile.values, r1.metadata.variables || {}, oldProfile?.values, oldMetadata.variables);
|
|
149
150
|
})) {
|
|
150
151
|
return false;
|
|
151
152
|
}
|
|
152
153
|
}
|
|
153
154
|
const cmpCtx = {
|
|
154
155
|
...ctx,
|
|
155
|
-
owner: ctx.
|
|
156
|
+
owner: ctx.app,
|
|
156
157
|
curPath: '',
|
|
157
158
|
newMetadataComponents: r1.metadata.components,
|
|
158
159
|
newProfileComponents: r1.profile.components,
|
|
@@ -162,8 +163,9 @@ export var ProcessorFactory;
|
|
|
162
163
|
if (!(_validateComponents(cmpCtx) && (await _configureComponents(cmpCtx)))) {
|
|
163
164
|
return false;
|
|
164
165
|
}
|
|
165
|
-
ctx.
|
|
166
|
-
ctx.
|
|
166
|
+
_configureLogChannels(ctx.app, r1.metadata.logChannels, r1.profile.settings?.logs?.channels, '', ctx.options?.logSink);
|
|
167
|
+
ctx.app[AppFactory.METADATA_KEY] = r1.metadata;
|
|
168
|
+
ctx.app[AppFactory.PROFILE_KEY] = r1.profile;
|
|
167
169
|
return true;
|
|
168
170
|
}
|
|
169
171
|
function _validateComponents(ctx) {
|
|
@@ -199,7 +201,7 @@ export var ProcessorFactory;
|
|
|
199
201
|
});
|
|
200
202
|
}
|
|
201
203
|
async function _configureComponents(ctx) {
|
|
202
|
-
const { newMetadataComponents, newProfileComponents, oldMetadataComponents, oldProfileComponents, curPath, owner, stackExecutor,
|
|
204
|
+
const { newMetadataComponents, newProfileComponents, oldMetadataComponents, oldProfileComponents, curPath, owner, stackExecutor, app, } = ctx;
|
|
203
205
|
if (!newMetadataComponents)
|
|
204
206
|
return true;
|
|
205
207
|
owner.components = owner.components || {};
|
|
@@ -224,7 +226,7 @@ export var ProcessorFactory;
|
|
|
224
226
|
const compClass = await compReg.getClass();
|
|
225
227
|
const values = { ...newChildProfile.values };
|
|
226
228
|
componentInstance = new compClass({
|
|
227
|
-
|
|
229
|
+
app: app,
|
|
228
230
|
parent: owner,
|
|
229
231
|
name: key,
|
|
230
232
|
path: componentPath,
|
|
@@ -238,6 +240,7 @@ export var ProcessorFactory;
|
|
|
238
240
|
componentInstance.values = {};
|
|
239
241
|
_patchValues(ctx, componentInstance, componentInstance.values, '', newChildProfile.values || {}, newChildMetadata.variables || {}, oldChildProfile?.values, oldChildMetadata?.variables);
|
|
240
242
|
}
|
|
243
|
+
_configureLogChannels(componentInstance, newChildMetadata.logChannels, newChildProfile.settings?.logs?.channels, componentPath, ctx.options?.logSink);
|
|
241
244
|
/** Create the child logger */
|
|
242
245
|
componentInstance.logger = owner.logger?.child({
|
|
243
246
|
component: componentPath,
|
|
@@ -286,5 +289,21 @@ export var ProcessorFactory;
|
|
|
286
289
|
}
|
|
287
290
|
}
|
|
288
291
|
}
|
|
289
|
-
|
|
290
|
-
|
|
292
|
+
/**
|
|
293
|
+
* Creates an element's log channels on first configuration - assigning
|
|
294
|
+
* each to its property - and applies the profile's settings to them on
|
|
295
|
+
* every one
|
|
296
|
+
*/
|
|
297
|
+
function _configureLogChannels(element, definitions, settings, source, sink) {
|
|
298
|
+
for (const [name, definition] of Object.entries(definitions || {})) {
|
|
299
|
+
let channel = element.logChannels[name];
|
|
300
|
+
if (!channel) {
|
|
301
|
+
channel = new LogChannelWriter(definition, source, sink);
|
|
302
|
+
element.logChannels[name] = channel;
|
|
303
|
+
if (definition.propertyKey)
|
|
304
|
+
element[definition.propertyKey] = channel;
|
|
305
|
+
}
|
|
306
|
+
channel.configure(settings?.[name], sink);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
})(AppFactory || (AppFactory = {}));
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { BaseElement } from './base-element.js';
|
|
2
|
-
export declare abstract class
|
|
2
|
+
export declare abstract class AppBase<TEvents extends AppBase.Events = AppBase.Events> extends BaseElement<TEvents> {
|
|
3
3
|
dataDirectory?: string;
|
|
4
|
-
constructor(init:
|
|
4
|
+
constructor(init: AppBase.InitArgs);
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* @namespace
|
|
8
8
|
*/
|
|
9
|
-
export declare namespace
|
|
9
|
+
export declare namespace AppBase {
|
|
10
10
|
interface Events extends BaseElement.Events {
|
|
11
11
|
}
|
|
12
12
|
interface InitArgs extends BaseElement.InitArgs {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseElement } from './base-element.js';
|
|
2
|
+
export class AppBase extends BaseElement {
|
|
3
|
+
dataDirectory;
|
|
4
|
+
constructor(init) {
|
|
5
|
+
super(init);
|
|
6
|
+
this.dataDirectory = init.dataDirectory;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
const APP_BASE_TOKEN = Symbol.for(AppBase.name);
|
|
10
|
+
AppBase.prototype[APP_BASE_TOKEN] = true;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { LogChannel } from '../decorators/log-channel.decorator.js';
|
|
1
2
|
import type { ILogger } from '../interfaces/index.js';
|
|
2
3
|
import { ServiceStatus } from '../models/index.js';
|
|
3
4
|
import type { ComponentBase } from './component-base.js';
|
|
@@ -11,6 +12,8 @@ export declare abstract class BaseElement<TEvents extends BaseElement.Events = B
|
|
|
11
12
|
readonly name: string;
|
|
12
13
|
logger?: ILogger;
|
|
13
14
|
components: Record<string, ComponentBase>;
|
|
15
|
+
/** The element's log channels by name; see `@LogChannel` */
|
|
16
|
+
readonly logChannels: Record<string, LogChannel>;
|
|
14
17
|
values: Record<string, any>;
|
|
15
18
|
constructor(init: BaseElement.InitArgs);
|
|
16
19
|
get status(): ServiceStatus;
|
package/classes/base-element.js
CHANGED
|
@@ -8,6 +8,8 @@ export class BaseElement extends Runnable {
|
|
|
8
8
|
name;
|
|
9
9
|
logger;
|
|
10
10
|
components = {};
|
|
11
|
+
/** The element's log channels by name; see `@LogChannel` */
|
|
12
|
+
logChannels = {};
|
|
11
13
|
values;
|
|
12
14
|
constructor(init) {
|
|
13
15
|
super(init);
|
|
@@ -88,4 +90,3 @@ export class BaseElement extends Runnable {
|
|
|
88
90
|
super.onStatusChange();
|
|
89
91
|
}
|
|
90
92
|
}
|
|
91
|
-
//# sourceMappingURL=base-element.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import type { AppBase } from './app-base.js';
|
|
1
2
|
import { BaseElement } from './base-element.js';
|
|
2
|
-
import type { ProcessorBase } from './processor-base.js';
|
|
3
3
|
export declare class ComponentBase<TEvents extends ComponentBase.Events = ComponentBase.Events> extends BaseElement<TEvents> {
|
|
4
4
|
protected _context: ComponentBase.Context;
|
|
5
|
-
readonly
|
|
6
|
-
readonly parent:
|
|
5
|
+
readonly app: AppBase;
|
|
6
|
+
readonly parent: AppBase | ComponentBase;
|
|
7
7
|
readonly path: string;
|
|
8
8
|
constructor(init: ComponentBase.InitArgs);
|
|
9
9
|
}
|
|
@@ -14,12 +14,12 @@ export declare namespace ComponentBase {
|
|
|
14
14
|
interface Events extends BaseElement.Events {
|
|
15
15
|
}
|
|
16
16
|
interface InitArgs extends BaseElement.InitArgs {
|
|
17
|
-
|
|
18
|
-
parent:
|
|
17
|
+
app: AppBase;
|
|
18
|
+
parent: AppBase | ComponentBase;
|
|
19
19
|
path: string;
|
|
20
20
|
}
|
|
21
21
|
interface Context extends BaseElement.Context {
|
|
22
|
-
parent:
|
|
22
|
+
parent: AppBase | ComponentBase;
|
|
23
23
|
name: string;
|
|
24
24
|
path: string;
|
|
25
25
|
}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { BaseElement } from './base-element.js';
|
|
2
2
|
export class ComponentBase extends BaseElement {
|
|
3
|
-
|
|
3
|
+
app;
|
|
4
4
|
parent;
|
|
5
5
|
path;
|
|
6
6
|
constructor(init) {
|
|
7
7
|
super(init);
|
|
8
|
-
this.
|
|
8
|
+
this.app = init.app;
|
|
9
9
|
this.parent = init.parent;
|
|
10
10
|
this.path = init.path;
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
const COMPONENT_BASE_TOKEN = Symbol.for(ComponentBase.name);
|
|
14
14
|
ComponentBase.prototype[COMPONENT_BASE_TOKEN] = true;
|
|
15
|
-
//# sourceMappingURL=component-base.js.map
|
package/classes/frame-stream.js
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { LogChannel } from '../decorators/log-channel.decorator.js';
|
|
2
|
+
import { LogChannelKind, type LogChannelMetadata, type LogChannelSettings, LogLevel } from '../models/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* The LogChannel a `@LogChannel` property holds: it applies the channel's
|
|
5
|
+
* settings and hands what passes them to the worker's sink.
|
|
6
|
+
*/
|
|
7
|
+
export declare class LogChannelWriter implements LogChannel {
|
|
8
|
+
readonly metadata: LogChannelMetadata;
|
|
9
|
+
/** The path of the element it belongs to; '' for the app */
|
|
10
|
+
readonly source: string;
|
|
11
|
+
protected _sink?: LogChannel.Sink | undefined;
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
level?: LogLevel;
|
|
14
|
+
/** The events written; all when not set */
|
|
15
|
+
events?: Set<string>;
|
|
16
|
+
constructor(metadata: LogChannelMetadata,
|
|
17
|
+
/** The path of the element it belongs to; '' for the app */
|
|
18
|
+
source: string, _sink?: LogChannel.Sink | undefined);
|
|
19
|
+
get name(): string;
|
|
20
|
+
get fullName(): string;
|
|
21
|
+
get kind(): LogChannelKind;
|
|
22
|
+
/** Applies the profile's settings over the definition's defaults */
|
|
23
|
+
configure(settings?: LogChannelSettings, sink?: LogChannel.Sink | undefined): void;
|
|
24
|
+
write(record: LogChannel.Record): void;
|
|
25
|
+
fatal(message: string, fields?: Record<string, any>): void;
|
|
26
|
+
error(message: string, fields?: Record<string, any>): void;
|
|
27
|
+
warn(message: string, fields?: Record<string, any>): void;
|
|
28
|
+
info(message: string, fields?: Record<string, any>): void;
|
|
29
|
+
verbose(message: string, fields?: Record<string, any>): void;
|
|
30
|
+
debug(message: string, fields?: Record<string, any>): void;
|
|
31
|
+
trace(message: string, fields?: Record<string, any>): void;
|
|
32
|
+
}
|