@toa.io/core 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 +11 -0
- package/package.json +2 -2
- package/src/call.js +7 -1
- package/src/context.js +2 -0
- package/src/contract/request.js +5 -1
- package/src/contract/schemas/index.js +1 -0
- package/src/contract/schemas/source.yaml +23 -0
- package/src/receiver.js +7 -0
- package/test/contract/request.test.js +39 -0
- package/types/context.d.ts +3 -0
- package/types/extensions.d.ts +1 -1
- package/types/index.ts +1 -1
- package/types/request.d.ts +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
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
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **core:** identify the origin of a call with `request.source` ([9da6b66](https://github.com/toa-io/toa/commit/9da6b66df852690351a1e82c7b8cc176fd89774a))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [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
18
|
|
|
8
19
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/core",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.262",
|
|
4
4
|
"description": "Toa Core",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -27,5 +27,5 @@
|
|
|
27
27
|
"openspan": "1.0.0-alpha.254",
|
|
28
28
|
"uuid": "11.1.1"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "e14059cf5cc364d933f2a4b3d7114f3b5ec0764f"
|
|
31
31
|
}
|
package/src/call.js
CHANGED
|
@@ -8,12 +8,14 @@ const { Err } = require('error-value')
|
|
|
8
8
|
class Call extends Connector {
|
|
9
9
|
#transmitter
|
|
10
10
|
#contract
|
|
11
|
+
#source
|
|
11
12
|
|
|
12
|
-
constructor (transmitter, contract) {
|
|
13
|
+
constructor (transmitter, contract, source) {
|
|
13
14
|
super()
|
|
14
15
|
|
|
15
16
|
this.#transmitter = transmitter
|
|
16
17
|
this.#contract = contract
|
|
18
|
+
this.#source = source
|
|
17
19
|
|
|
18
20
|
this.depends(transmitter)
|
|
19
21
|
}
|
|
@@ -21,6 +23,10 @@ class Call extends Connector {
|
|
|
21
23
|
async invoke (request = {}) {
|
|
22
24
|
request.input ??= null
|
|
23
25
|
|
|
26
|
+
// the caller may have attributed the call itself, as the node bridge does
|
|
27
|
+
if (this.#source !== undefined)
|
|
28
|
+
request.source ??= this.#source
|
|
29
|
+
|
|
24
30
|
this.#contract.fit(request)
|
|
25
31
|
|
|
26
32
|
// avoid validation on the recipient's side
|
package/src/context.js
CHANGED
|
@@ -9,6 +9,7 @@ class Context extends Connector {
|
|
|
9
9
|
env
|
|
10
10
|
name
|
|
11
11
|
aspects
|
|
12
|
+
locator
|
|
12
13
|
|
|
13
14
|
#local
|
|
14
15
|
#discover
|
|
@@ -20,6 +21,7 @@ class Context extends Connector {
|
|
|
20
21
|
this.env = process.env.TOA_ENV
|
|
21
22
|
this.name = process.env.TOA_CONTEXT
|
|
22
23
|
this.aspects = aspects
|
|
24
|
+
this.locator = local?.locator
|
|
23
25
|
|
|
24
26
|
this.#local = local
|
|
25
27
|
this.#discover = discover
|
package/src/contract/request.js
CHANGED
|
@@ -24,7 +24,11 @@ class Request extends Contract {
|
|
|
24
24
|
static schema (definition, entity) {
|
|
25
25
|
const schema = {
|
|
26
26
|
type: 'object',
|
|
27
|
-
properties: {
|
|
27
|
+
properties: {
|
|
28
|
+
authentic: { type: 'boolean' },
|
|
29
|
+
task: { type: 'boolean' },
|
|
30
|
+
source: structuredClone(schemas.source)
|
|
31
|
+
},
|
|
28
32
|
additionalProperties: true
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Origin of a call, see toa.core.Source.
|
|
2
|
+
# Deliberately permissive on required properties: the contract throws on a mismatch,
|
|
3
|
+
# and a strict union would turn a partially stamped source into a failed business call.
|
|
4
|
+
# `additionalProperties: false` combined with `removeAdditional` is what matters here —
|
|
5
|
+
# it strips whatever a peer puts in, bounding the cardinality of the resulting map.
|
|
6
|
+
type: object
|
|
7
|
+
properties:
|
|
8
|
+
namespace:
|
|
9
|
+
type: string
|
|
10
|
+
maxLength: 64
|
|
11
|
+
component:
|
|
12
|
+
type: string
|
|
13
|
+
maxLength: 64
|
|
14
|
+
operation:
|
|
15
|
+
type: string
|
|
16
|
+
maxLength: 64
|
|
17
|
+
event:
|
|
18
|
+
type: string
|
|
19
|
+
maxLength: 64
|
|
20
|
+
service:
|
|
21
|
+
type: string
|
|
22
|
+
maxLength: 64
|
|
23
|
+
additionalProperties: false
|
package/src/receiver.js
CHANGED
|
@@ -26,6 +26,9 @@ class Receiver extends Connector {
|
|
|
26
26
|
/** @type {unknown[]} */
|
|
27
27
|
#arguments
|
|
28
28
|
|
|
29
|
+
/** @type {toa.core.Source} */
|
|
30
|
+
#origin
|
|
31
|
+
|
|
29
32
|
#local
|
|
30
33
|
|
|
31
34
|
#bridge
|
|
@@ -41,6 +44,7 @@ class Receiver extends Connector {
|
|
|
41
44
|
this.#label = definition.label ?? operation
|
|
42
45
|
this.#destination = definition.destination ?? this.#label
|
|
43
46
|
this.#arguments = definition.arguments
|
|
47
|
+
this.#origin = definition.origin
|
|
44
48
|
|
|
45
49
|
this.#local = local
|
|
46
50
|
this.#bridge = bridge
|
|
@@ -59,6 +63,9 @@ class Receiver extends Connector {
|
|
|
59
63
|
|
|
60
64
|
add(request, extensions)
|
|
61
65
|
|
|
66
|
+
// set after `add`, so that a message field can not spoof the origin
|
|
67
|
+
if (this.#origin !== undefined) request.source = this.#origin
|
|
68
|
+
|
|
62
69
|
// continue the trace from the producer span
|
|
63
70
|
const remote = telemetry === undefined ? null : decode(telemetry)
|
|
64
71
|
const task = () => this.#process(request)
|
|
@@ -110,3 +110,42 @@ describe('schema', () => {
|
|
|
110
110
|
expect(objects.limit).toBeDefined()
|
|
111
111
|
})
|
|
112
112
|
})
|
|
113
|
+
|
|
114
|
+
describe('source', () => {
|
|
115
|
+
const schemas = require('@toa.io/schemas')
|
|
116
|
+
|
|
117
|
+
const compile = (definition, entity) =>
|
|
118
|
+
schemas.schema(Request.schema(definition, entity), { removeAdditional: true })
|
|
119
|
+
|
|
120
|
+
it('should declare source', () => {
|
|
121
|
+
const schema = Request.schema({}, dummy)
|
|
122
|
+
|
|
123
|
+
expect(schema.properties.source).toBeDefined()
|
|
124
|
+
expect(schema.properties.source.additionalProperties).toStrictEqual(false)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('should pass known source variants', () => {
|
|
128
|
+
const schema = compile({}, undefined)
|
|
129
|
+
|
|
130
|
+
for (const source of [
|
|
131
|
+
{ namespace: 'a', component: 'b', operation: 'c' },
|
|
132
|
+
{ namespace: 'a', component: 'b', event: 'c' },
|
|
133
|
+
{ service: 'exposition' }
|
|
134
|
+
]) {
|
|
135
|
+
const request = { input: null, query: null, source }
|
|
136
|
+
|
|
137
|
+
expect(schema.fit(request)).toStrictEqual(null)
|
|
138
|
+
expect(request.source).toStrictEqual(source)
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
// `source` crosses the wire and keys the introspection map, so whatever
|
|
143
|
+
// a peer adds to it must not survive
|
|
144
|
+
it('should strip unknown source properties', () => {
|
|
145
|
+
const schema = compile({}, undefined)
|
|
146
|
+
const request = { input: null, query: null, source: { service: 'exposition', evil: 'x' } }
|
|
147
|
+
|
|
148
|
+
expect(schema.fit(request)).toStrictEqual(null)
|
|
149
|
+
expect(request.source).toStrictEqual({ service: 'exposition' })
|
|
150
|
+
})
|
|
151
|
+
})
|
package/types/context.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as _request from './request'
|
|
2
|
+
import { Locator } from './locator'
|
|
2
3
|
import * as _reply from './reply'
|
|
3
4
|
import * as _extensions from './extensions'
|
|
4
5
|
import * as _connector from './connector'
|
|
@@ -6,6 +7,8 @@ import * as _connector from './connector'
|
|
|
6
7
|
export interface Context extends _connector.Connector{
|
|
7
8
|
aspects: _extensions.Aspect[]
|
|
8
9
|
|
|
10
|
+
locator: Locator
|
|
11
|
+
|
|
9
12
|
/**
|
|
10
13
|
* Calls local endpoint
|
|
11
14
|
*/
|
package/types/extensions.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export interface Factory {
|
|
|
20
20
|
|
|
21
21
|
storage? (storage: _storages.Storage): _storages.Storage
|
|
22
22
|
|
|
23
|
-
emitter? (emitter: _bindings.Emitter, label: string): _bindings.Emitter
|
|
23
|
+
emitter? (emitter: _bindings.Emitter, label: string, locator: _core.Locator): _bindings.Emitter
|
|
24
24
|
|
|
25
25
|
receiver? (receiver: _core.Receiver, locator: _core.Locator): _core.Receiver
|
|
26
26
|
}
|
package/types/index.ts
CHANGED
|
@@ -12,4 +12,4 @@ export type { Exception } from './exception'
|
|
|
12
12
|
export { Locator } from './locator'
|
|
13
13
|
export type { Receiver } from './receiver'
|
|
14
14
|
export type { Message } from './message'
|
|
15
|
-
export type { Request, Query, Reply } from './request'
|
|
15
|
+
export type { Request, Query, Reply, Source } from './request'
|
package/types/request.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Exception } from './exception'
|
|
|
2
2
|
|
|
3
3
|
export interface Query {
|
|
4
4
|
id?: string
|
|
5
|
+
ids?: Array<string>
|
|
5
6
|
criteria?: string
|
|
6
7
|
search?: string
|
|
7
8
|
sample?: number
|
|
@@ -13,12 +14,21 @@ export interface Query {
|
|
|
13
14
|
deleted?: boolean
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Origin of a call. Stamped by the caller, sanitized by the request contract.
|
|
19
|
+
*/
|
|
20
|
+
export type Source =
|
|
21
|
+
| { namespace: string, component: string, operation: string }
|
|
22
|
+
| { namespace: string, component: string, event: string }
|
|
23
|
+
| { service: string }
|
|
24
|
+
|
|
16
25
|
export interface Request {
|
|
17
26
|
input?: any
|
|
18
27
|
query?: Query
|
|
19
28
|
authentic?: boolean
|
|
20
29
|
task?: boolean
|
|
21
30
|
telemetry?: string // W3C traceparent
|
|
31
|
+
source?: Source
|
|
22
32
|
}
|
|
23
33
|
|
|
24
34
|
export interface Reply {
|