@toa.io/boot 1.0.0-alpha.259 → 1.0.0-alpha.262

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 CHANGED
@@ -3,6 +3,22 @@
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.262](https://github.com/toa-io/toa/compare/v1.0.0-alpha.261...v1.0.0-alpha.262) (2026-08-28)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **boot:** let the composition own the process discovery ([2201e88](https://github.com/toa-io/toa/commit/2201e8852517fd1d2822c775c9b126eb60399580))
12
+
13
+
14
+ ### Features
15
+
16
+ * **core:** identify the origin of a call with `request.source` ([9da6b66](https://github.com/toa-io/toa/commit/9da6b66df852690351a1e82c7b8cc176fd89774a))
17
+
18
+
19
+
20
+
21
+
6
22
  # [1.0.0-alpha.259](https://github.com/toa-io/toa/compare/v1.0.0-alpha.258...v1.0.0-alpha.259) (2026-08-24)
7
23
 
8
24
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/boot",
3
- "version": "1.0.0-alpha.259",
3
+ "version": "1.0.0-alpha.262",
4
4
  "description": "Toa Boot",
5
5
  "author": "temich <tema.gurtovoy@gmail.com>",
6
6
  "homepage": "https://github.com/toa-io/toa#readme",
@@ -20,14 +20,14 @@
20
20
  "test": "echo \"Error: run tests from root\" && exit 1"
21
21
  },
22
22
  "dependencies": {
23
- "@toa.io/core": "1.0.0-alpha.259",
23
+ "@toa.io/core": "1.0.0-alpha.262",
24
24
  "@toa.io/filesystem": "1.0.0-alpha.254",
25
25
  "@toa.io/generic": "1.0.0-alpha.254",
26
- "@toa.io/norm": "1.0.0-alpha.259",
26
+ "@toa.io/norm": "1.0.0-alpha.262",
27
27
  "@toa.io/schemas": "1.0.0-alpha.254",
28
28
  "clone-deep": "4.0.1",
29
29
  "dotenv": "16.1.1",
30
30
  "openspan": "1.0.0-alpha.254"
31
31
  },
32
- "gitHead": "3f557c2f855f078163128c317e7cb2f3629968aa"
32
+ "gitHead": "e14059cf5cc364d933f2a4b3d7114f3b5ec0764f"
33
33
  }
package/src/call.js CHANGED
@@ -4,12 +4,13 @@ const { Call, Transmission } = require('@toa.io/core')
4
4
 
5
5
  const boot = require('./index')
6
6
 
7
- const call = (locator, endpoint, definition, entity) => {
7
+ // eslint-disable-next-line max-params
8
+ const call = (locator, endpoint, definition, entity, source) => {
8
9
  const consumers = boot.bindings.consume(locator, endpoint, definition.bindings)
9
10
  const transmission = new Transmission(consumers)
10
11
  const contract = boot.contract.request(definition, entity)
11
12
 
12
- return new Call(transmission, contract)
13
+ return new Call(transmission, contract, source)
13
14
  }
14
15
 
15
16
  exports.call = call
@@ -62,6 +62,14 @@ async function composition (paths, options) {
62
62
 
63
63
  const composition = new Composition(expositions.flat(), producers.concat(settles), receivers.flat(), tenants.flat())
64
64
 
65
+ /*
66
+ * A lookup that is never answered holds a connection open, and whoever
67
+ * awaits it has nothing to disconnect — the remote it would belong to does
68
+ * not exist yet. The composition owns the process's discovery instead, so
69
+ * an unanswered lookup cannot outlive it.
70
+ */
71
+ composition.depends(await boot.discovery.discovery())
72
+
65
73
  return boot.extensions.manage(composition)
66
74
  } catch (exception) {
67
75
  await Promise.all(expositions.flat().map((connector) => connector.disconnect(true)))
package/src/context.js CHANGED
@@ -5,7 +5,7 @@ const { Context, Locator } = require('@toa.io/core')
5
5
  const boot = require('./index')
6
6
 
7
7
  const context = async (manifest) => {
8
- const local = await boot.remote(manifest.locator, manifest)
8
+ const local = await boot.remote(manifest.locator, undefined, manifest)
9
9
  const aspects = boot.extensions.aspects(manifest)
10
10
 
11
11
  const lookup = async (namespace, name) => {
package/src/emission.js CHANGED
@@ -10,7 +10,7 @@ const emission = (definitions, locator, context) => {
10
10
 
11
11
  const events = Object.entries(definitions).map(([label, definition]) => {
12
12
  const emitter = boot.bindings.emit(definition.binding, locator, label)
13
- const decorator = extensions.emitter(emitter, label)
13
+ const decorator = extensions.emitter(emitter, label, locator)
14
14
  const bridge = boot.bridge.event(definition.bridge, definition.path, label, context)
15
15
 
16
16
  return new Event({ ...definition, label: `${locator.id}.${label}` }, decorator, bridge)
@@ -5,13 +5,14 @@ const { instances } = require('./instances')
5
5
  /**
6
6
  * @param {toa.core.bindings.Emitter} emitter
7
7
  * @param {string} label
8
+ * @param {toa.core.Locator} locator
8
9
  * @returns {toa.core.bindings.Emitter}
9
10
  */
10
- const emitter = (emitter, label) => {
11
+ const emitter = (emitter, label, locator) => {
11
12
  let decorated = emitter
12
13
 
13
14
  for (const factory of Object.values(instances)) {
14
- if (factory.emitter !== undefined) decorated = factory.emitter(decorated, label)
15
+ if (factory.emitter !== undefined) decorated = factory.emitter(decorated, label, locator)
15
16
  }
16
17
 
17
18
  return decorated
package/src/receivers.js CHANGED
@@ -9,15 +9,19 @@ const receivers = async (manifest, component) => {
9
9
  if (manifest.receivers === undefined) return []
10
10
 
11
11
  const receivers = []
12
- const local = await boot.remote(manifest.locator, manifest)
12
+ const local = await boot.remote(manifest.locator, undefined, manifest)
13
13
 
14
14
  for (const [label, definition] of Object.entries(manifest.receivers)) {
15
15
  const locator = Locator.parse(label)
16
16
  const source = definition.source ? Locator.parse(definition.source) : locator
17
- const destination = `${source.id}.${label.split('.').pop()}`
17
+ const event = label.split('.').pop()
18
+ const destination = `${source.id}.${event}`
19
+
20
+ // the origin of the calls this receiver makes to its local operation
21
+ const origin = { namespace: source.namespace, component: source.name, event }
18
22
 
19
23
  const bridge = definition.bridge !== undefined ? boot.bridge.receiver(definition.bridge, manifest.path, label) : undefined
20
- const receiver = new Receiver({ ...definition, label, destination }, local, bridge)
24
+ const receiver = new Receiver({ ...definition, label, destination, origin }, local, bridge)
21
25
  const decorator = extensions.receiver(receiver, manifest.locator)
22
26
 
23
27
  const transport = definition.binding ?? await resolveBinding(locator, label)
package/src/remote.js CHANGED
@@ -6,7 +6,12 @@ const { remap } = require('@toa.io/generic')
6
6
 
7
7
  const boot = require('./index')
8
8
 
9
- const remote = async (locator, manifest) => {
9
+ /**
10
+ * @param {toa.core.Locator} locator
11
+ * @param {toa.core.Source} [source] the origin stamped on every call made through this remote
12
+ * @param {toa.norm.Component} [manifest] skips discovery when the manifest is already known
13
+ */
14
+ const remote = async (locator, source, manifest) => {
10
15
  let discovery
11
16
 
12
17
  if (manifest === undefined) {
@@ -18,7 +23,8 @@ const remote = async (locator, manifest) => {
18
23
 
19
24
  const calls = manifest.operations === undefined
20
25
  ? {}
21
- : remap(manifest.operations, (definition, endpoint) => boot.call(locator, endpoint, definition, manifest.entity))
26
+ : remap(manifest.operations,
27
+ (definition, endpoint) => boot.call(locator, endpoint, definition, manifest.entity, source))
22
28
 
23
29
  const remote = new Remote(locator, calls)
24
30
 
package/types/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export * as bindings from './bindings'
5
5
 
6
6
  export async function composition (paths: string[], options?: composition.Options): Promise<core.Connector>
7
7
 
8
- export async function remote (locator: core.Locator): Promise<core.Remote>
8
+ export async function remote (locator: core.Locator, source?: core.Source): Promise<core.Remote>
9
9
 
10
10
  export async function receive<T = any> (
11
11
  label: string,