@toa.io/extensions.cadence 1.0.0-alpha.284 → 1.0.0-alpha.287
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 +3 -3
- package/LICENSE +22 -0
- package/components/cadence.metronome/manifest.toa.yaml +22 -28
- package/components/cadence.metronome/migrations/0001-system-properties.yaml +14 -0
- package/components/cadence.metronome/migrations/0002-indexes.yaml +5 -0
- package/components/cadence.metronome/migrations/0003-pending-index.yaml +16 -0
- package/components/cadence.metronome/migrations/0004-retention.yaml +15 -0
- package/components/cadence.metronome/operations/delay.js +1 -1
- package/components/cadence.metronome/operations/settle.js +8 -4
- package/components/cadence.metronome/types/toa.d.ts +5 -5
- package/package.json +6 -5
- package/readme.md +35 -21
- package/schemas/declaration.cos.yaml +0 -1
- package/source/Aspect.ts +19 -10
- package/source/Composition.ts +4 -4
- package/source/Dispatcher.test.ts +240 -32
- package/source/Dispatcher.ts +145 -32
- package/source/Factory.ts +13 -10
- package/source/Local.ts +5 -4
- package/source/Pulse.test.ts +48 -19
- package/source/Pulse.ts +30 -21
- package/source/const.ts +7 -1
- package/source/context.ts +2 -2
- package/source/deployment.ts +10 -5
- package/source/manifest.test.ts +9 -6
- package/source/manifest.ts +24 -11
- package/transpiled/Aspect.d.ts +0 -1
- package/transpiled/Aspect.js +11 -5
- package/transpiled/Aspect.js.map +1 -1
- package/transpiled/Composition.js.map +1 -1
- package/transpiled/Dispatcher.d.ts +22 -4
- package/transpiled/Dispatcher.js +111 -18
- package/transpiled/Dispatcher.js.map +1 -1
- package/transpiled/Factory.d.ts +1 -1
- package/transpiled/Factory.js.map +1 -1
- package/transpiled/Local.d.ts +2 -1
- package/transpiled/Local.js.map +1 -1
- package/transpiled/Pulse.d.ts +2 -1
- package/transpiled/Pulse.js +14 -5
- package/transpiled/Pulse.js.map +1 -1
- package/transpiled/const.d.ts +6 -0
- package/transpiled/const.js +6 -0
- package/transpiled/const.js.map +1 -1
- package/transpiled/context.d.ts +1 -1
- package/transpiled/deployment.js +5 -2
- package/transpiled/deployment.js.map +1 -1
- package/transpiled/manifest.js +6 -3
- package/transpiled/manifest.js.map +1 -1
- package/tsconfig.tsbuildinfo +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
# [1.0.0-alpha.
|
|
6
|
+
# [1.0.0-alpha.287](https://github.com/toa-io/toa/compare/v1.0.0-alpha.286...v1.0.0-alpha.287) (2026-09-06)
|
|
7
7
|
|
|
8
|
-
###
|
|
8
|
+
### Bug Fixes
|
|
9
9
|
|
|
10
|
-
* **cadence:**
|
|
10
|
+
* **cadence:** the scan reads what is owed, and nothing that is done ([581610e](https://github.com/toa-io/toa/commit/581610e87ac54c42491c882d5749ff3307700d35))
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2020-present Artem Gurtovoi
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -5,35 +5,29 @@ name: metronome
|
|
|
5
5
|
cadence: ~
|
|
6
6
|
|
|
7
7
|
entity:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
description: Which dispatcher takes this row, as the outbox partitions its lanes
|
|
13
|
-
type: integer
|
|
14
|
-
due:
|
|
15
|
-
description: When the call is to be made, in milliseconds since the epoch
|
|
16
|
-
type: integer
|
|
17
|
-
expires:
|
|
18
|
-
description: >
|
|
19
|
-
After this the call is not made at all. A scan bounds on it, so a call nothing was
|
|
20
|
-
running to make in time is a row nobody reads, rather than an event anything sees.
|
|
21
|
-
type: integer
|
|
22
|
-
endpoint:
|
|
23
|
-
description: What to call, as `namespace.component.operation`
|
|
24
|
-
type: string
|
|
25
|
-
request:
|
|
26
|
-
description: The request to make, as it was handed over
|
|
27
|
-
type: object
|
|
28
|
-
required:
|
|
29
|
-
- lane
|
|
30
|
-
- due
|
|
31
|
-
- expires
|
|
32
|
-
- endpoint
|
|
33
|
-
index:
|
|
8
|
+
properties:
|
|
9
|
+
lane:
|
|
10
|
+
description: Which dispatcher takes this row, as the outbox partitions its lanes
|
|
11
|
+
type: integer
|
|
34
12
|
due:
|
|
35
|
-
|
|
36
|
-
|
|
13
|
+
description: When the call is to be made, in milliseconds since the epoch
|
|
14
|
+
type: integer
|
|
15
|
+
expires:
|
|
16
|
+
description: >
|
|
17
|
+
After this the call is not made at all. A scan bounds on it, so a call nothing was
|
|
18
|
+
running to make in time is a row nobody reads, rather than an event anything sees.
|
|
19
|
+
type: integer
|
|
20
|
+
endpoint:
|
|
21
|
+
description: What to call, as `namespace.component.operation`
|
|
22
|
+
type: string
|
|
23
|
+
request:
|
|
24
|
+
description: The request to make, as it was handed over
|
|
25
|
+
type: object
|
|
26
|
+
required:
|
|
27
|
+
- lane
|
|
28
|
+
- due
|
|
29
|
+
- expires
|
|
30
|
+
- endpoint
|
|
37
31
|
|
|
38
32
|
# `enumerate` reads what is due and `terminate` cancels one; both come from the prototype.
|
|
39
33
|
operations:
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# 1.0.0-alpha.286 renamed the four system properties of a record. A database written before it
|
|
2
|
+
# holds them under the old names, where nothing reads them: such a record is never created,
|
|
3
|
+
# never updated, never deleted, and at version zero.
|
|
4
|
+
#
|
|
5
|
+
# `$rename` leaves a record that has none of them alone, so this is a no-op for a component
|
|
6
|
+
# that has only ever run this release.
|
|
7
|
+
- update:
|
|
8
|
+
filter: {}
|
|
9
|
+
update:
|
|
10
|
+
$rename:
|
|
11
|
+
_version: VERSION
|
|
12
|
+
_created: CREATED
|
|
13
|
+
_updated: UPDATED
|
|
14
|
+
_deleted: DELETED
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# The index holds what is still owed, and nothing else.
|
|
2
|
+
#
|
|
3
|
+
# Without the filter a scan walks every row the collection has ever held: the criteria bounds
|
|
4
|
+
# `due` from above and not below, and `DELETED` is not in the index, so every tombstone is
|
|
5
|
+
# fetched and discarded on the way to the few rows that are live. The cost of a pass grows with
|
|
6
|
+
# the age of the deployment until it outlives its own interval.
|
|
7
|
+
#
|
|
8
|
+
# The name is the one 0002 gave it, deliberately: an index whose declaration changed is dropped
|
|
9
|
+
# and made again.
|
|
10
|
+
- index:
|
|
11
|
+
name: index_due
|
|
12
|
+
keys:
|
|
13
|
+
lane: asc
|
|
14
|
+
due: asc
|
|
15
|
+
partial:
|
|
16
|
+
DELETED: null
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# A settled row is kept, and not kept forever.
|
|
2
|
+
#
|
|
3
|
+
# `DELETED` is what `settle` writes and what the runtime holds as a date, so the row ages out
|
|
4
|
+
# on the moment its call was disposed of. A row still owed has `DELETED: null`, and the TTL
|
|
5
|
+
# monitor passes over a record whose field is not a date — so nothing waiting to be called can
|
|
6
|
+
# be reaped by this, however long it has been waiting.
|
|
7
|
+
#
|
|
8
|
+
# Thirty days. The record answers what was asked for and when it was disposed of, which is a
|
|
9
|
+
# question asked while an incident is recent; a year of it is a collection nobody reads and
|
|
10
|
+
# everybody stores.
|
|
11
|
+
- index:
|
|
12
|
+
name: index_deleted
|
|
13
|
+
keys:
|
|
14
|
+
DELETED: asc
|
|
15
|
+
ttl: 2592000
|
|
@@ -8,7 +8,7 @@ import { LANES } from '@toa.io/extensions.cadence'
|
|
|
8
8
|
* row has no immediate path to settle, so nothing is gained, and an even spread is what the
|
|
9
9
|
* dispatchers want.
|
|
10
10
|
*/
|
|
11
|
-
export function transition
|
|
11
|
+
export function transition(input, object) {
|
|
12
12
|
const due = Date.now() + input.interval
|
|
13
13
|
|
|
14
14
|
object.lane = Math.floor(Math.random() * LANES)
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The rows whose calls have been
|
|
3
|
-
*
|
|
2
|
+
* The rows whose calls have been disposed of — made, or found past the bound their caller gave
|
|
3
|
+
* them. They are tombstoned rather than removed: the record of what was asked for outlives the
|
|
4
|
+
* call, and a query answers only what is still owed.
|
|
5
|
+
*
|
|
6
|
+
* `DELETED` is also what the retention index reaps by, so that the record outlives the call
|
|
7
|
+
* without outliving the deployment.
|
|
4
8
|
*/
|
|
5
|
-
export function transition
|
|
9
|
+
export function transition(_, objects) {
|
|
6
10
|
const now = Date.now()
|
|
7
11
|
|
|
8
|
-
for (const object of objects) object.
|
|
12
|
+
for (const object of objects) object.DELETED = now
|
|
9
13
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Written by `toa types`. Every run rewrites it.
|
|
2
2
|
// What a manifest does not state belongs in a file of your own.
|
|
3
3
|
|
|
4
|
-
import type { Query } from '@toa.io/core'
|
|
4
|
+
import type { Query } from '@toa.io/core/types'
|
|
5
5
|
import type { Readable } from 'node:stream'
|
|
6
6
|
|
|
7
7
|
export interface Entity {
|
|
@@ -16,10 +16,10 @@ export interface Entity {
|
|
|
16
16
|
/** The request to make, as it was handed over */
|
|
17
17
|
request?: Record<string, unknown>
|
|
18
18
|
id: string
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
VERSION?: number
|
|
20
|
+
CREATED?: number
|
|
21
|
+
UPDATED?: number
|
|
22
|
+
DELETED?: number | null
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export type DelayInput = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/extensions.cadence",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.287",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Toa Schedule",
|
|
6
6
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
@@ -18,11 +18,12 @@
|
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@toa.io/core": "1.0.0-alpha.
|
|
22
|
-
"@toa.io/schemas": "1.0.0-alpha.
|
|
23
|
-
"openspan": "1.0.0-alpha.
|
|
21
|
+
"@toa.io/core": "1.0.0-alpha.287",
|
|
22
|
+
"@toa.io/schemas": "1.0.0-alpha.287",
|
|
23
|
+
"openspan": "1.0.0-alpha.286"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"transpile": "tsc"
|
|
27
|
-
}
|
|
27
|
+
},
|
|
28
|
+
"gitHead": "5c7944a70c16065ab6372072385cc1f02f5db77c"
|
|
28
29
|
}
|
package/readme.md
CHANGED
|
@@ -14,9 +14,9 @@ at all.
|
|
|
14
14
|
```yaml
|
|
15
15
|
# manifest.toa.yaml
|
|
16
16
|
cadence:
|
|
17
|
-
sweep:
|
|
18
|
-
cycle: 86400
|
|
19
|
-
intervals: 24
|
|
17
|
+
sweep: # an operation of this component
|
|
18
|
+
cycle: 86400 # seconds one whole cycle takes
|
|
19
|
+
intervals: 24 # what it is split into, so one call an hour
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
The gap between calls is `cycle / intervals`, derived rather than declared, so the two cannot
|
|
@@ -26,13 +26,13 @@ declares:
|
|
|
26
26
|
```yaml
|
|
27
27
|
# manifest.toa.yaml
|
|
28
28
|
cadence:
|
|
29
|
-
sweep: 3600
|
|
29
|
+
sweep: 3600 # once an hour
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
The operation is called with the cycle and the interval as its input:
|
|
33
33
|
|
|
34
34
|
```javascript
|
|
35
|
-
async function sweep
|
|
35
|
+
async function sweep({ n, i }, context) {}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
`n` is `intervals` and `i` is which of them this call is for, from `0` to `n - 1`. They are there
|
|
@@ -77,22 +77,25 @@ either answer put to everyone who wanted an operation called every hour is a wor
|
|
|
77
77
|
picking one.
|
|
78
78
|
|
|
79
79
|
`intervals` is not a replica count. With `intervals: 24` and three replicas each makes eight of
|
|
80
|
-
the day's calls: the cycle is spread over
|
|
80
|
+
the day's calls: the cycle is spread over _time_, not over the fleet. Replicas beyond `intervals`
|
|
81
81
|
make none.
|
|
82
82
|
|
|
83
83
|
## Delay
|
|
84
84
|
|
|
85
85
|
```javascript
|
|
86
|
-
const id = await context.delay(
|
|
87
|
-
|
|
86
|
+
const id = await context.delay(
|
|
87
|
+
'mail.sender.remind',
|
|
88
|
+
{ input: { user } },
|
|
89
|
+
{ interval: 7 * 24 * 3600 * 1000, overdue: null }
|
|
90
|
+
)
|
|
88
91
|
|
|
89
92
|
await context.delay.cancel(id)
|
|
90
93
|
```
|
|
91
94
|
|
|
92
|
-
|
|
|
93
|
-
|
|
94
|
-
| `interval` | milliseconds from now
|
|
95
|
-
| `overdue`
|
|
95
|
+
| | |
|
|
96
|
+
| ---------- | --------------------------------------------------------------------------- |
|
|
97
|
+
| `interval` | milliseconds from now |
|
|
98
|
+
| `overdue` | milliseconds the call may be late and still be made, or `null` for no bound |
|
|
96
99
|
|
|
97
100
|
The call is made once the delay has passed, and waits for the target where it is not there to
|
|
98
101
|
take it. The id it answers cancels it, and `cancel` raises where the id was never issued.
|
|
@@ -111,11 +114,11 @@ cadence: ~
|
|
|
111
114
|
ordinary path has: a call is made at the moment it is due. How much is left of that in practice
|
|
112
115
|
depends on how coarsely the calls are looked over — see [Discreteness](#discreteness).
|
|
113
116
|
|
|
114
|
-
|
|
|
115
|
-
|
|
116
|
-
| `null`
|
|
117
|
-
| `0`
|
|
118
|
-
| a number | made if no more than that many milliseconds late
|
|
117
|
+
| | |
|
|
118
|
+
| -------- | ------------------------------------------------------- |
|
|
119
|
+
| `null` | no bound: made whenever it can be, however late that is |
|
|
120
|
+
| `0` | on time or never |
|
|
121
|
+
| a number | made if no more than that many milliseconds late |
|
|
119
122
|
|
|
120
123
|
**There is no default, and it is stated on every call.** Only the caller knows whether a late
|
|
121
124
|
call is still the right call — an unpaid order expires on time or not at all, a report is wanted
|
|
@@ -139,12 +142,23 @@ it already past its bound and leaves it. State an `overdue` several times `discr
|
|
|
139
142
|
`null`.
|
|
140
143
|
|
|
141
144
|
**A cancellation is reliable while the call is further out than `discreteness`**, and is a race
|
|
142
|
-
closer than that, where the call may already be on its way.
|
|
145
|
+
closer than that, where the call may already be on its way. What bounds it is the period between
|
|
146
|
+
passes: a cancelled call stops being owed, the next pass stops reading it, and a call taken in
|
|
147
|
+
hand is given up again when that happens.
|
|
148
|
+
|
|
149
|
+
**A call is due by the clock of whichever replica took the `delay`**, and made by the clock of
|
|
150
|
+
whichever one dispatches it. The overlap covers the disagreement between two machines kept in
|
|
151
|
+
ordinary time; nothing here measures it.
|
|
143
152
|
|
|
144
153
|
So `discreteness` and `overdue` are chosen together against what the application needs. A call
|
|
145
154
|
that must be made within seconds of its time, or cancellable within seconds of it, needs a
|
|
146
155
|
`discreteness` of seconds — at the cost of looking the calls over that much more often.
|
|
147
156
|
|
|
157
|
+
**A pass takes a bounded number of calls**, 200 to a replica, oldest first. Where more than that
|
|
158
|
+
come due to one replica in one period, the rest are taken on a later pass and are late by however
|
|
159
|
+
long that took; where it is logged, the rate is past what one period can carry. Replicas divide
|
|
160
|
+
the lanes between them, so the ceiling is per replica rather than for the application.
|
|
161
|
+
|
|
148
162
|
### What to expect
|
|
149
163
|
|
|
150
164
|
**A call may be made more than once**, so where a second one would cost something, the target
|
|
@@ -179,10 +193,10 @@ may no longer be one it accepts. Either way the attempt is spent.
|
|
|
179
193
|
```yaml
|
|
180
194
|
# context.toa.yaml
|
|
181
195
|
cadence:
|
|
182
|
-
discreteness: 60
|
|
196
|
+
discreteness: 60 # seconds between passes over the calls waiting to be made
|
|
183
197
|
```
|
|
184
198
|
|
|
185
199
|
`discreteness` is how often the calls waiting to be made are looked over. It defaults to 60,
|
|
186
|
-
which is what an application that states nothing gets. It
|
|
187
|
-
|
|
200
|
+
which is what an application that states nothing gets. It sets how small an `overdue` is worth
|
|
201
|
+
stating, and it is the floor under how closely a delayed call can be cancelled — see
|
|
188
202
|
[Discreteness](#discreteness) — and lowering it costs a pass that runs more often.
|
package/source/Aspect.ts
CHANGED
|
@@ -17,14 +17,13 @@ interface Input {
|
|
|
17
17
|
* handing over the call it should have scheduled loses the call, and there is no way for this
|
|
18
18
|
* to know. Where the semantics allow it, hand the call over first.
|
|
19
19
|
*
|
|
20
|
-
* @implements {toa.core.extensions.Aspect}
|
|
21
20
|
*/
|
|
22
21
|
export class Aspect extends Connector {
|
|
23
22
|
public readonly name = 'delay'
|
|
24
23
|
|
|
25
24
|
private readonly metronome: Local
|
|
26
25
|
|
|
27
|
-
public constructor
|
|
26
|
+
public constructor(metronome: Local) {
|
|
28
27
|
super()
|
|
29
28
|
|
|
30
29
|
this.metronome = metronome
|
|
@@ -34,18 +33,28 @@ export class Aspect extends Connector {
|
|
|
34
33
|
|
|
35
34
|
// named rather than forwarded, so that the connector's lifecycle is not reachable from an
|
|
36
35
|
// algorithm — the same reason the atom aspect names its own
|
|
37
|
-
public async invoke
|
|
36
|
+
public async invoke(method: string, ...args: any[]): Promise<unknown> {
|
|
38
37
|
switch (method) {
|
|
39
|
-
case 'delay':
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
case 'delay':
|
|
39
|
+
return await this.delay(args[0], args[1], args[2])
|
|
40
|
+
case 'cancel':
|
|
41
|
+
return await this.cancel(args[0])
|
|
42
|
+
default:
|
|
43
|
+
throw new Error(`Delay aspect has no '${method}' method`)
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
/** Answers the id the call was given, which is what cancels it. */
|
|
46
|
-
private async delay
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
private async delay(
|
|
49
|
+
endpoint: string,
|
|
50
|
+
request: object | null,
|
|
51
|
+
options: Options
|
|
52
|
+
): Promise<unknown> {
|
|
53
|
+
const input: Input = {
|
|
54
|
+
endpoint,
|
|
55
|
+
interval: options.interval,
|
|
56
|
+
overdue: options.overdue
|
|
57
|
+
}
|
|
49
58
|
|
|
50
59
|
// a call that takes no request carries none, rather than a null one
|
|
51
60
|
if (request !== null && request !== undefined) input.request = request
|
|
@@ -58,7 +67,7 @@ export class Aspect extends Connector {
|
|
|
58
67
|
* nothing to terminate and raises; one whose call has already been made has a row still, and
|
|
59
68
|
* terminating it again is not an error.
|
|
60
69
|
*/
|
|
61
|
-
private async cancel
|
|
70
|
+
private async cancel(id: string): Promise<unknown> {
|
|
62
71
|
return await this.metronome.invoke('terminate', { query: { id }, input: null })
|
|
63
72
|
}
|
|
64
73
|
}
|
package/source/Composition.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { Dirent } from 'node:fs'
|
|
|
5
5
|
import type { Host } from './Factory.js'
|
|
6
6
|
|
|
7
7
|
/** The components this extension ships, which run inside its own service. */
|
|
8
|
-
export function components
|
|
8
|
+
export function components(): Components {
|
|
9
9
|
const labels: string[] = []
|
|
10
10
|
const paths: string[] = []
|
|
11
11
|
|
|
@@ -20,13 +20,13 @@ export function components (): Components {
|
|
|
20
20
|
export class Composition extends Connector {
|
|
21
21
|
private readonly host: Host
|
|
22
22
|
|
|
23
|
-
public constructor
|
|
23
|
+
public constructor(host: Host) {
|
|
24
24
|
super()
|
|
25
25
|
|
|
26
26
|
this.host = host
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
protected override async open
|
|
29
|
+
protected override async open(): Promise<void> {
|
|
30
30
|
const composition = await this.host.composition(components().paths)
|
|
31
31
|
|
|
32
32
|
await composition.connect()
|
|
@@ -35,7 +35,7 @@ export class Composition extends Connector {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
function entries
|
|
38
|
+
function entries(): Dirent[] {
|
|
39
39
|
return readdirSync(ROOT, { withFileTypes: true }).filter((entry) => entry.isDirectory())
|
|
40
40
|
}
|
|
41
41
|
|