@toa.io/boot 1.0.0-alpha.31 → 1.0.0-alpha.310

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 (59) hide show
  1. package/CHANGELOG.md +217 -0
  2. package/package.json +11 -8
  3. package/src/atom.js +41 -0
  4. package/src/atomicity.js +11 -0
  5. package/src/bindings/broadcast.js +3 -6
  6. package/src/bindings/constants.js +1 -3
  7. package/src/bindings/consume.js +8 -8
  8. package/src/bindings/emit.js +3 -6
  9. package/src/bindings/factory.js +5 -9
  10. package/src/bindings/inbound.js +11 -0
  11. package/src/bindings/index.js +7 -13
  12. package/src/bindings/outbound.js +10 -0
  13. package/src/bindings/produce.js +40 -18
  14. package/src/bindings/receive.js +3 -6
  15. package/src/bridge.js +22 -16
  16. package/src/call.js +22 -9
  17. package/src/cascade.js +16 -10
  18. package/src/component.js +90 -32
  19. package/src/composition.js +102 -15
  20. package/src/context.js +7 -8
  21. package/src/contract.js +11 -12
  22. package/src/emission.js +21 -14
  23. package/src/env.js +19 -12
  24. package/src/events.js +27 -0
  25. package/src/extensions/aspects.js +4 -8
  26. package/src/extensions/component.js +4 -8
  27. package/src/extensions/context.js +4 -8
  28. package/src/extensions/destinations.js +27 -0
  29. package/src/extensions/emitter.js +7 -9
  30. package/src/extensions/index.js +10 -19
  31. package/src/extensions/instances.js +2 -4
  32. package/src/extensions/load.js +7 -7
  33. package/src/extensions/manage.js +15 -0
  34. package/src/extensions/receiver.js +5 -9
  35. package/src/extensions/resolve.js +36 -11
  36. package/src/extensions/storage.js +6 -9
  37. package/src/extensions/tenants.js +5 -9
  38. package/src/guards.js +20 -0
  39. package/src/host.js +29 -0
  40. package/src/inbox.js +10 -0
  41. package/src/index.js +27 -34
  42. package/src/manifest.js +78 -36
  43. package/src/manifest.test.js +85 -8
  44. package/src/map.js +98 -0
  45. package/src/operation.js +25 -13
  46. package/src/outbox.js +22 -0
  47. package/src/rc.js +5 -0
  48. package/src/receivers.js +53 -23
  49. package/src/remote.js +37 -22
  50. package/src/span.js +19 -0
  51. package/src/storage.js +50 -16
  52. package/src/storage.test.js +57 -0
  53. package/src/workload.js +281 -0
  54. package/src/workload.test.js +321 -0
  55. package/types/bindings.d.ts +6 -2
  56. package/types/index.d.ts +62 -10
  57. package/types/manifest.d.ts +5 -4
  58. package/src/discovery.js +0 -43
  59. package/src/exposition.js +0 -17
package/CHANGELOG.md ADDED
@@ -0,0 +1,217 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ # [1.0.0-alpha.310](https://github.com/toa-io/toa/compare/v1.0.0-alpha.309...v1.0.0-alpha.310) (2026-09-16)
7
+
8
+ **Note:** Version bump only for package @toa.io/boot
9
+
10
+
11
+
12
+
13
+
14
+ # [1.0.0-alpha.309](https://github.com/toa-io/toa/compare/v1.0.0-alpha.308...v1.0.0-alpha.309) (2026-09-16)
15
+
16
+ **Note:** Version bump only for package @toa.io/boot
17
+
18
+
19
+
20
+
21
+
22
+ # [1.0.0-alpha.308](https://github.com/toa-io/toa/compare/v1.0.0-alpha.307...v1.0.0-alpha.308) (2026-09-15)
23
+
24
+ **Note:** Version bump only for package @toa.io/boot
25
+
26
+
27
+
28
+
29
+
30
+ # [1.0.0-alpha.307](https://github.com/toa-io/toa/compare/v1.0.0-alpha.306...v1.0.0-alpha.307) (2026-09-15)
31
+
32
+ **Note:** Version bump only for package @toa.io/boot
33
+
34
+
35
+
36
+
37
+
38
+ # [1.0.0-alpha.306](https://github.com/toa-io/toa/compare/v1.0.0-alpha.305...v1.0.0-alpha.306) (2026-09-14)
39
+
40
+ * refactor(core)!: name the quiesce hooks pause and unpause ([6e4e5f5](https://github.com/toa-io/toa/commit/6e4e5f55d43f03ea95ca8bbdaae57b949564dfa2))
41
+ * feat(boot)!: a process can be halted and come back ([7196fa5](https://github.com/toa-io/toa/commit/7196fa51a9c882e84c3767a4fdd329fd2df319f5))
42
+
43
+ ### Bug Fixes
44
+
45
+ * **boot:** declare what a workload does with a quiesce ([0e1521d](https://github.com/toa-io/toa/commit/0e1521d7abae3a3860a29978d267927d814c1d3a))
46
+ * **boot:** keep a halted process alive until it comes back ([3d3cc23](https://github.com/toa-io/toa/commit/3d3cc23835f836f9f98b1d9a448090a2b0d473c8))
47
+
48
+ ### Features
49
+
50
+ * **boot:** let a process go quiet and be let go again ([0fc3e66](https://github.com/toa-io/toa/commit/0fc3e66f217ab45e85f70271ab0768232b3fa088))
51
+ * **boot:** quiet a tree before taking it down ([7a339ca](https://github.com/toa-io/toa/commit/7a339caea4499509b55daf91061fc9836c0f6e68))
52
+ * **bridges.node:** let a component stop what it started and start it again ([d10d5d1](https://github.com/toa-io/toa/commit/d10d5d16fcd181e717d9d2cef4c7814ae8f2a93f))
53
+
54
+ ### BREAKING CHANGES
55
+
56
+ * `Host.halt` is `Host.stop`.
57
+ * `Host` gains `gate` and `halt`, and `Factory.service` may answer a gate. An
58
+ extension that gates nothing keeps its connections through a halt.
59
+
60
+
61
+ # [1.0.0-alpha.305](https://github.com/toa-io/toa/compare/v1.0.0-alpha.304...v1.0.0-alpha.305) (2026-09-13)
62
+
63
+ ### Features
64
+
65
+ * **core:** refuse a call that writes, made under a request that only reads ([92951d0](https://github.com/toa-io/toa/commit/92951d0f7b95bd5b838097dd6a42db5586968d0b))
66
+
67
+
68
+ # [1.0.0-alpha.304](https://github.com/toa-io/toa/compare/v1.0.0-alpha.303...v1.0.0-alpha.304) (2026-09-13)
69
+
70
+ **Note:** Version bump only for package @toa.io/boot
71
+
72
+
73
+
74
+
75
+
76
+ # [1.0.0-alpha.303](https://github.com/toa-io/toa/compare/v1.0.0-alpha.302...v1.0.0-alpha.303) (2026-09-12)
77
+
78
+ **Note:** Version bump only for package @toa.io/boot
79
+
80
+
81
+
82
+
83
+
84
+ # [1.0.0-alpha.302](https://github.com/toa-io/toa/compare/v1.0.0-alpha.301...v1.0.0-alpha.302) (2026-09-11)
85
+
86
+ ### Features
87
+
88
+ * **boot:** a run command may wait until the component is served ([0f66bed](https://github.com/toa-io/toa/commit/0f66bedf7b54dc9c1397f7f32bbccbffde7288ca))
89
+
90
+
91
+ # [1.0.0-alpha.301](https://github.com/toa-io/toa/compare/v1.0.0-alpha.300...v1.0.0-alpha.301) (2026-09-11)
92
+
93
+ **Note:** Version bump only for package @toa.io/boot
94
+
95
+
96
+
97
+
98
+
99
+ # [1.0.0-alpha.300](https://github.com/toa-io/toa/compare/v1.0.0-alpha.299...v1.0.0-alpha.300) (2026-09-11)
100
+
101
+ * feat(boot)!: a process is a thing, and an extension may keep something in one ([528d6cd](https://github.com/toa-io/toa/commit/528d6cdd307b45a6c30b6a184d7e06b3328cecf8))
102
+ * feat(core)!: an operation may ask to run once ([dca616c](https://github.com/toa-io/toa/commit/dca616cb380a7a389e277875d3bd5ca55a6e4d45))
103
+
104
+ ### Features
105
+
106
+ * **core:** a call carries what it is, and a chain of them carries it down ([ebd7769](https://github.com/toa-io/toa/commit/ebd776984a79adb9bf4a97b680128be1efab856f))
107
+ * **core:** a call may name the process it goes to, and wait for a set time ([7d8adb2](https://github.com/toa-io/toa/commit/7d8adb2772a95ff45ae5374efdedfb5a857fbbe9))
108
+
109
+ ### BREAKING CHANGES
110
+
111
+ * `Storage.store`, `.upsert` and `.ensure` take one more
112
+ argument, and `Storage` has two more members. A connector that ignores them
113
+ works exactly as it did; a component that asks it for `once` is refused at
114
+ boot. See migrations/299.md.
115
+ * a composition booted directly has no readiness probe. Readiness is
116
+ the process's, and a composition is not a process. `stage.workload` boots one where a
117
+ suite needs it.
118
+
119
+
120
+ # [1.0.0-alpha.299](https://github.com/toa-io/toa/compare/v1.0.0-alpha.298...v1.0.0-alpha.299) (2026-09-10)
121
+
122
+ ### Features
123
+
124
+ * **bindings.amqp:** a binding carries a channel, addressed by label ([17cf178](https://github.com/toa-io/toa/commit/17cf1782d1c47d033c02f99947b766eb9d45df75))
125
+ * **convergence:** deployments of one context converge ([8a70343](https://github.com/toa-io/toa/commit/8a70343cf6953aab58d4a25bac215508ff8d9a37))
126
+ * **core:** an outbox row is published to destinations ([cfb77b4](https://github.com/toa-io/toa/commit/cfb77b4826ff0f9560769a0996981e143d6525af))
127
+
128
+
129
+ # [1.0.0-alpha.298](https://github.com/toa-io/toa/compare/v1.0.0-alpha.297...v1.0.0-alpha.298) (2026-09-08)
130
+
131
+ **Note:** Version bump only for package @toa.io/boot
132
+
133
+
134
+
135
+
136
+
137
+ # [1.0.0-alpha.297](https://github.com/toa-io/toa/compare/v1.0.0-alpha.296...v1.0.0-alpha.297) (2026-09-08)
138
+
139
+ **Note:** Version bump only for package @toa.io/boot
140
+
141
+
142
+
143
+
144
+
145
+ # [1.0.0-alpha.296](https://github.com/toa-io/toa/compare/v1.0.0-alpha.295...v1.0.0-alpha.296) (2026-09-08)
146
+
147
+ **Note:** Version bump only for package @toa.io/boot
148
+
149
+
150
+
151
+
152
+
153
+ # [1.0.0-alpha.295](https://github.com/toa-io/toa/compare/v1.0.0-alpha.294...v1.0.0-alpha.295) (2026-09-07)
154
+
155
+ **Note:** Version bump only for package @toa.io/boot
156
+
157
+
158
+
159
+
160
+
161
+ # [1.0.0-alpha.294](https://github.com/toa-io/toa/compare/v1.0.0-alpha.293...v1.0.0-alpha.294) (2026-09-07)
162
+
163
+ **Note:** Version bump only for package @toa.io/boot
164
+
165
+
166
+
167
+
168
+
169
+ # [1.0.0-alpha.293](https://github.com/toa-io/toa/compare/v1.0.0-alpha.292...v1.0.0-alpha.293) (2026-09-07)
170
+
171
+ **Note:** Version bump only for package @toa.io/boot
172
+
173
+
174
+
175
+
176
+
177
+ # [1.0.0-alpha.292](https://github.com/toa-io/toa/compare/v1.0.0-alpha.291...v1.0.0-alpha.292) (2026-09-07)
178
+
179
+ ### Features
180
+
181
+ * **definitions:** the version of Toa is the definitions package's ([3d0272e](https://github.com/toa-io/toa/commit/3d0272ea0ab862f4b6c2e58a2f003f92d0f8a87f))
182
+ * **definitions:** what a package declares is read from one package ([7052341](https://github.com/toa-io/toa/commit/70523411b5d9e2b204c999aa02365173f3bb518d))
183
+ * **norm:** a package's definition is read by one resolver ([bffd41c](https://github.com/toa-io/toa/commit/bffd41c8d18c42786b0bf321623088b9dabc4724))
184
+
185
+
186
+ # [1.0.0-alpha.291](https://github.com/toa-io/toa/compare/v1.0.0-alpha.290...v1.0.0-alpha.291) (2026-09-07)
187
+
188
+ **Note:** Version bump only for package @toa.io/boot
189
+
190
+
191
+
192
+
193
+
194
+ # [1.0.0-alpha.289](https://github.com/toa-io/toa/compare/v1.0.0-alpha.288...v1.0.0-alpha.289) (2026-09-07)
195
+
196
+ * A deploy moves only what changed, and a component sees none of the runtime's environment (#1073) ([f38e3db](https://github.com/toa-io/toa/commit/f38e3db533f24db866c57bfa1ef294eff1eaf499)), closes [#1073](https://github.com/toa-io/toa/issues/1073) [#1064](https://github.com/toa-io/toa/issues/1064) [#1066](https://github.com/toa-io/toa/issues/1066) [#1067](https://github.com/toa-io/toa/issues/1067) [#1068](https://github.com/toa-io/toa/issues/1068) [#1069](https://github.com/toa-io/toa/issues/1069) [#1071](https://github.com/toa-io/toa/issues/1071) [#1070](https://github.com/toa-io/toa/issues/1070) [#1072](https://github.com/toa-io/toa/issues/1072)
197
+
198
+ ### BREAKING CHANGES
199
+
200
+ * a component that read `process.env.TOA_*` reads `context` instead;
201
+ `echo(input)` no longer substitutes from the environment; a bash operation sees no
202
+ `TOA_*`; images no longer set `USER node` — see migrations/289.md.
203
+
204
+
205
+ # [1.0.0-alpha.288](https://github.com/toa-io/toa/compare/v1.0.0-alpha.287...v1.0.0-alpha.288) (2026-09-06)
206
+
207
+ **Note:** Version bump only for package @toa.io/boot
208
+
209
+
210
+
211
+
212
+
213
+ # [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)
214
+
215
+ ### Bug Fixes
216
+
217
+ * **boot:** a discovery belongs to the connection that made it ([48e1c8f](https://github.com/toa-io/toa/commit/48e1c8f668b1853134ae9fb2349c485e6da66c28))
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@toa.io/boot",
3
- "version": "1.0.0-alpha.31",
3
+ "version": "1.0.0-alpha.310",
4
+ "type": "module",
4
5
  "description": "Toa Boot",
5
6
  "author": "temich <tema.gurtovoy@gmail.com>",
6
7
  "homepage": "https://github.com/toa-io/toa#readme",
@@ -20,13 +21,15 @@
20
21
  "test": "echo \"Error: run tests from root\" && exit 1"
21
22
  },
22
23
  "dependencies": {
23
- "@toa.io/core": "1.0.0-alpha.31",
24
- "@toa.io/filesystem": "1.0.0-alpha.31",
25
- "@toa.io/generic": "1.0.0-alpha.31",
26
- "@toa.io/norm": "1.0.0-alpha.31",
27
- "@toa.io/schema": "1.0.0-alpha.31",
24
+ "@toa.io/atomicity": "1.0.0-alpha.310",
25
+ "@toa.io/core": "1.0.0-alpha.310",
26
+ "@toa.io/definitions": "1.0.0-alpha.310",
27
+ "@toa.io/generic": "1.0.0-alpha.310",
28
+ "@toa.io/norm": "1.0.0-alpha.310",
29
+ "@toa.io/schemas": "1.0.0-alpha.310",
28
30
  "clone-deep": "4.0.1",
29
- "dotenv": "16.1.1"
31
+ "dotenv": "17.4.2",
32
+ "openspan": "1.0.0-alpha.305"
30
33
  },
31
- "gitHead": "91839a488176853a0731f49abc70dc7103ed7cca"
34
+ "gitHead": "d952c57f77279729e26d52d50c6df47138ad0a4f"
32
35
  }
package/src/atom.js ADDED
@@ -0,0 +1,41 @@
1
+ import { Connector } from '@toa.io/core'
2
+
3
+ import * as boot from './index.js'
4
+
5
+ /**
6
+ * The atom as a system aspect. Every component has `context.atom`, with nothing declared in its
7
+ * manifest and nothing of its own to configure.
8
+ *
9
+ * @implements {import('@toa.io/core/types').extensions.Aspect}
10
+ */
11
+ class Aspect extends Connector {
12
+ name = 'atom'
13
+
14
+ #atom
15
+
16
+ constructor(atom) {
17
+ super()
18
+
19
+ this.#atom = atom
20
+
21
+ this.depends(atom)
22
+ }
23
+
24
+ // the methods are named rather than forwarded, so that the connector's lifecycle is not
25
+ // reachable from an algorithm
26
+ invoke(method, ...args) {
27
+ switch (method) {
28
+ case 'slots':
29
+ return this.#atom.slots(...args)
30
+ case 'meter':
31
+ return this.#atom.meter(...args)
32
+ case 'lock':
33
+ return this.#atom.lock(...args)
34
+ default:
35
+ throw new Error(`Atom aspect has no '${method}' method`)
36
+ }
37
+ }
38
+ }
39
+
40
+ /** @param {string} group */
41
+ export const atom = (group) => new Aspect(boot.atomicity(group))
@@ -0,0 +1,11 @@
1
+ import { Factory } from '@toa.io/atomicity'
2
+
3
+ /**
4
+ * What the replicas of one group decide together. Every component has one, whether or not there
5
+ * is anything to coordinate through: without a Redis nothing is owned and nothing is metered —
6
+ * see the connector's readme.
7
+ *
8
+ * @param {string} group
9
+ * @returns {import('@toa.io/core/types').atomicity.Atom}
10
+ */
11
+ export const atomicity = (group) => new Factory().atom(group)
@@ -1,7 +1,4 @@
1
- 'use strict'
1
+ import { factory } from './factory.js'
2
2
 
3
- const { factory } = require('./factory')
4
-
5
- const broadcast = (channel, group, binding = '@toa.io/bindings.amqp') => factory(binding).broadcast(channel, group)
6
-
7
- exports.broadcast = broadcast
3
+ export const broadcast = async (channel, group, binding = '@toa.io/bindings.amqp') =>
4
+ (await factory(binding)).broadcast(channel, group)
@@ -1,3 +1 @@
1
- 'use strict'
2
-
3
- exports.LOOP = '@toa.io/bindings.loop'
1
+ export const LOOP = '@toa.io/bindings.loop'
@@ -1,9 +1,9 @@
1
- 'use strict'
1
+ import { LOOP } from './constants.js'
2
+ import { factory } from './factory.js'
2
3
 
3
- const { LOOP } = require('./constants')
4
- const { factory } = require('./factory')
5
-
6
- const consume = (locator, endpoint, bindings) =>
7
- [LOOP].concat(bindings).map((binding) => factory(binding).consumer(locator, endpoint))
8
-
9
- exports.consume = consume
4
+ export const consume = async (locator, endpoint, bindings) =>
5
+ await Promise.all(
6
+ [LOOP]
7
+ .concat(bindings)
8
+ .map(async (binding) => (await factory(binding)).consumer(locator, endpoint))
9
+ )
@@ -1,7 +1,4 @@
1
- 'use strict'
1
+ import { factory } from './factory.js'
2
2
 
3
- const { factory } = require('./factory')
4
-
5
- const emit = (binding, locator, label) => factory(binding).emitter(locator, label)
6
-
7
- exports.emit = emit
3
+ export const emit = async (binding, locator, label) =>
4
+ (await factory(binding)).emitter(locator, label)
@@ -1,15 +1,11 @@
1
- 'use strict'
2
-
3
1
  let instances = {}
4
2
 
5
- const factory = (binding) => {
6
- if (instances[binding] === undefined) instances[binding] = new (require(binding).Factory)()
3
+ // the promise is what is remembered, so two components cannot each make a factory
4
+ export const factory = async (binding) => {
5
+ instances[binding] ??= import(binding).then(({ Factory }) => new Factory())
7
6
 
8
- return instances[binding]
7
+ return await instances[binding]
9
8
  }
10
9
 
11
10
  // for testing purposes
12
- const reset = () => (instances = {})
13
-
14
- exports.factory = factory
15
- exports.reset = reset
11
+ export const reset = () => (instances = {})
@@ -0,0 +1,11 @@
1
+ import { factory } from './factory.js'
2
+
3
+ // eslint-disable-next-line max-params
4
+ export const inbound = async (binding, channel, uris, label, sink) => {
5
+ const instance = await factory(binding)
6
+
7
+ if (instance.inbound === undefined)
8
+ throw new Error(`Binding '${binding}' does not consume a channel`)
9
+
10
+ return instance.inbound(channel, uris, label, sink)
11
+ }
@@ -1,13 +1,7 @@
1
- 'use strict'
2
-
3
- const { broadcast } = require('./broadcast')
4
- const { consume } = require('./consume')
5
- const { emit } = require('./emit')
6
- const { produce } = require('./produce')
7
- const { receive } = require('./receive')
8
-
9
- exports.broadcast = broadcast
10
- exports.consume = consume
11
- exports.emit = emit
12
- exports.produce = produce
13
- exports.receive = receive
1
+ export { broadcast } from './broadcast.js'
2
+ export { consume } from './consume.js'
3
+ export { emit } from './emit.js'
4
+ export { inbound } from './inbound.js'
5
+ export { outbound } from './outbound.js'
6
+ export { produce } from './produce.js'
7
+ export { receive } from './receive.js'
@@ -0,0 +1,10 @@
1
+ import { factory } from './factory.js'
2
+
3
+ export const outbound = async (binding, channel, uris) => {
4
+ const instance = await factory(binding)
5
+
6
+ if (instance.outbound === undefined)
7
+ throw new Error(`Binding '${binding}' does not publish a channel`)
8
+
9
+ return instance.outbound(channel, uris)
10
+ }
@@ -1,28 +1,50 @@
1
- 'use strict'
1
+ import { definition } from '@toa.io/norm'
2
+ import { LOOP } from './constants.js'
3
+ import { factory } from './factory.js'
4
+
5
+ export const produce = async (component, operations) => {
6
+ const local = []
7
+ const other = []
8
+ const stateful = addressed(operations)
9
+
10
+ for (const [binding, endpoints] of group(operations)) {
11
+ const made = await factory(binding)
12
+ const carried = stateful.filter((endpoint) => endpoints.includes(endpoint))
13
+ const producer = made.producer(component.locator, endpoints, component, carried)
14
+ const { properties } = (await definition(binding)).module
15
+
16
+ if (properties.local === true) local.push(producer)
17
+ else other.push(producer)
18
+ }
2
19
 
3
- const { LOOP } = require('./constants')
4
- const { factory } = require('./factory')
20
+ return { local, other }
21
+ }
5
22
 
6
- const produce = (component, operations) => group(operations, (factory, endpoints) =>
7
- factory.producer(component.locator, endpoints, component))
23
+ /** The endpoints that take addressed calls only. */
24
+ const addressed = (operations) =>
25
+ operations === undefined
26
+ ? []
27
+ : Object.entries(operations)
28
+ .filter(([, operation]) => operation.stateful === true)
29
+ .map(([endpoint]) => endpoint)
8
30
 
9
- const group = (operations, callback) => {
31
+ /** The endpoints each binding carries, as entries. */
32
+ const group = (operations) => {
10
33
  const map = {}
11
34
 
12
- for (const [endpoint, operation] of Object.entries(operations)) {
13
- // noinspection JSUnresolvedVariable
14
- const bindings = global.TOA_INTEGRATION_BINDINGS_LOOP_DISABLED
15
- ? operation.bindings
16
- : [LOOP].concat(operation.bindings)
35
+ if (operations !== undefined)
36
+ for (const [endpoint, operation] of Object.entries(operations)) {
37
+ // noinspection JSUnresolvedVariable
38
+ const bindings = global.TOA_INTEGRATION_BINDINGS_LOOP_DISABLED
39
+ ? operation.bindings
40
+ : [LOOP].concat(operation.bindings)
17
41
 
18
- for (const binding of bindings) {
19
- if (!map[binding]) map[binding] = []
42
+ for (const binding of bindings) {
43
+ if (!map[binding]) map[binding] = []
20
44
 
21
- map[binding].push(endpoint)
45
+ map[binding].push(endpoint)
46
+ }
22
47
  }
23
- }
24
48
 
25
- return Object.entries(map).map(([binding, endpoints]) => callback(factory(binding), endpoints))
49
+ return Object.entries(map)
26
50
  }
27
-
28
- exports.produce = produce
@@ -1,7 +1,4 @@
1
- 'use strict'
1
+ import { factory } from './factory.js'
2
2
 
3
- const { factory } = require('./factory')
4
-
5
- const receive = (binding, locator, label, group, receiver) => factory(binding).receiver(locator, label, group, receiver)
6
-
7
- exports.receive = receive
3
+ export const receive = async (binding, locator, label, group, receiver) =>
4
+ (await factory(binding)).receiver(locator, label, group, receiver)
package/src/bridge.js CHANGED
@@ -1,28 +1,34 @@
1
- 'use strict'
2
-
3
- const algorithm = (bridge, path, endpoint, context) => {
4
- const algorithm = resolve(bridge).algorithm(path, endpoint, context)
1
+ export async function algorithm(bridge, path, endpoint, context) {
2
+ const factory = await resolve(bridge)
3
+ const algorithm = await factory.algorithm(path, endpoint, context)
5
4
 
6
5
  algorithm.depends(context)
7
6
 
8
7
  return algorithm
9
8
  }
10
9
 
11
- const event = (bridge, path, label, context) => resolve(bridge).event(path, label, context)
12
- const receiver = (bridge, path, label) => resolve(bridge).receiver(path, label)
10
+ export const event = async (bridge, path, label, context) =>
11
+ (await resolve(bridge)).event(path, label, context)
13
12
 
14
- const factories = {}
13
+ export const receiver = async (bridge, path, label) =>
14
+ (await resolve(bridge)).receiver(path, label)
15
15
 
16
- const resolve = (bridge) => {
17
- if (factories[bridge] === undefined) {
18
- const { Factory } = require(bridge)
16
+ export const guard = async (bridge, path, label, context) =>
17
+ (await resolve(bridge)).guard(path, label, context)
19
18
 
20
- factories[bridge] = new Factory()
21
- }
19
+ export async function rc(bridge, path, context) {
20
+ const factory = await resolve(bridge)
22
21
 
23
- return factories[bridge]
22
+ if (factory.rc === undefined) return
23
+
24
+ return factory.rc(path, context)
24
25
  }
25
26
 
26
- exports.algorithm = algorithm
27
- exports.event = event
28
- exports.receiver = receiver
27
+ const factories = {}
28
+
29
+ // the promise is what is remembered, so two boots cannot each make a factory
30
+ const resolve = async (bridge) => {
31
+ factories[bridge] ??= import(bridge).then(({ Factory }) => new Factory())
32
+
33
+ return await factories[bridge]
34
+ }
package/src/call.js CHANGED
@@ -1,15 +1,28 @@
1
- 'use strict'
1
+ import { Call, safe, Transmission } from '@toa.io/core'
2
2
 
3
- const { Call, Transmission } = require('@toa.io/core')
3
+ import * as boot from './index.js'
4
4
 
5
- const boot = require('./index')
6
-
7
- const call = (locator, endpoint, definition, entity) => {
8
- const consumers = boot.bindings.consume(locator, endpoint, definition.bindings)
5
+ // eslint-disable-next-line max-params
6
+ export const call = async (locator, endpoint, definition, entity, source) => {
7
+ const consumers = await boot.bindings.consume(locator, endpoint, definition.bindings)
9
8
  const transmission = new Transmission(consumers)
10
9
  const contract = boot.contract.request(definition, entity)
11
10
 
12
- return new Call(transmission, contract)
13
- }
11
+ const stateful = definition.stateful === true
14
12
 
15
- exports.call = call
13
+ /*
14
+ * An endpoint beginning with `.` is the runtime's own rather than an operation — a lookup, an
15
+ * exposition — so the safety of operations has nothing to say about it. `Component.invoke`
16
+ * counts it as no hop in a call chain for the same reason.
17
+ */
18
+ const readable = endpoint[0] === '.' || safe(definition.type)
19
+
20
+ return new Call(
21
+ transmission,
22
+ contract,
23
+ `${locator.id}.${endpoint}`,
24
+ source,
25
+ stateful,
26
+ readable
27
+ )
28
+ }
package/src/cascade.js CHANGED
@@ -1,16 +1,19 @@
1
- 'use strict'
1
+ import { Cascade } from '@toa.io/core'
2
2
 
3
- const { Cascade } = require('@toa.io/core')
3
+ import * as boot from './index.js'
4
4
 
5
- const boot = require('./index')
6
-
7
- const cascade = (manifest, endpoint, definition, context) => {
5
+ export async function cascade(manifest, endpoint, definition, context, preflight) {
8
6
  const bridges = []
9
7
 
10
8
  if (definition.forward) endpoint = definition.forward
11
9
 
12
10
  if (definition.bridge) {
13
- const bridge = boot.bridge.algorithm(definition.bridge, manifest.path, endpoint, context)
11
+ const bridge = await boot.bridge.algorithm(
12
+ definition.bridge,
13
+ manifest.path,
14
+ endpoint,
15
+ context
16
+ )
14
17
 
15
18
  bridges.unshift(bridge)
16
19
  }
@@ -22,12 +25,15 @@ const cascade = (manifest, endpoint, definition, context) => {
22
25
 
23
26
  if (operation === undefined) continue
24
27
 
25
- const bridge = boot.bridge.algorithm(operation.bridge, prototype.path, endpoint, context)
28
+ const bridge = await boot.bridge.algorithm(
29
+ operation.bridge,
30
+ prototype.path,
31
+ endpoint,
32
+ context
33
+ )
26
34
 
27
35
  bridges.unshift(bridge)
28
36
  }
29
37
 
30
- return new Cascade(bridges)
38
+ return new Cascade(bridges, preflight)
31
39
  }
32
-
33
- exports.cascade = cascade