@toa.io/core 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 +1 -185
- package/package.json +19 -7
- package/source/assignment.ts +27 -0
- package/{src/call.js → source/call.ts} +16 -21
- package/{src/cascade.js → source/cascade.ts} +6 -8
- package/{src/component.js → source/component.ts} +27 -25
- package/{src/composition.js → source/composition.ts} +9 -3
- package/{src/connector.js → source/connector.ts} +36 -55
- package/source/context.ts +67 -0
- package/source/contract/contract.ts +23 -0
- package/{src/contract/reply.js → source/contract/reply.ts} +26 -19
- package/source/contract/request.ts +85 -0
- package/source/contract/schemas.ts +39 -0
- package/{src/discovery.js → source/discovery.ts} +15 -8
- package/source/effect.ts +14 -0
- package/{src/emission.js → source/emission.ts} +5 -3
- package/source/entities/changeset.ts +37 -0
- package/source/entities/entity.ts +137 -0
- package/source/entities/factory.ts +52 -0
- package/source/entities/index.ts +4 -0
- package/{src/entities/newid.js → source/entities/newid.ts} +1 -1
- package/{src/entities/set.js → source/entities/set.ts} +8 -5
- package/source/event.ts +57 -0
- package/{src/exceptions.js → source/exceptions.ts} +52 -33
- package/source/exposition.ts +33 -0
- package/source/guard.ts +16 -0
- package/{src/index.js → source/index.ts} +8 -0
- package/{src/locator.js → source/locator.ts} +17 -30
- package/source/observation.ts +16 -0
- package/source/operation.ts +138 -0
- package/{src/outbox/outbox.js → source/outbox/outbox.ts} +87 -53
- package/source/query/criteria.ts +90 -0
- package/source/query/options.ts +35 -0
- package/{src/query.js → source/query.ts} +14 -17
- package/source/receiver.ts +120 -0
- package/source/reflection.ts +20 -0
- package/source/remote.ts +20 -0
- package/source/state.ts +179 -0
- package/source/transition.ts +79 -0
- package/{src/transmission.js → source/transmission.ts} +8 -8
- package/source/types/atomicity.ts +63 -0
- package/source/types/bindings.ts +59 -0
- package/source/types/bridges.ts +54 -0
- package/source/types/extensions.ts +89 -0
- package/{types → source/types}/index.ts +9 -16
- package/{types/message.d.ts → source/types/message.ts} +2 -1
- package/source/types/operations.ts +31 -0
- package/source/types/outbox.ts +35 -0
- package/source/types/receiver.ts +10 -0
- package/{types/request.d.ts → source/types/request.ts} +8 -9
- package/source/types/state.ts +9 -0
- package/source/types/storages.ts +129 -0
- package/source/unmanaged.ts +8 -0
- package/test/call.fixtures.js +3 -1
- package/test/call.test.js +28 -7
- package/test/component.test.js +10 -5
- package/test/connector.fixtures.js +7 -7
- package/test/connector.test.js +15 -2
- package/test/context.fixtures.js +1 -1
- package/test/context.test.js +4 -4
- package/test/contract/conditions.test.js +6 -2
- package/test/contract/contract.fixtures.js +3 -4
- package/test/contract/request.test.js +68 -34
- package/test/discovery.test.js +10 -3
- package/test/emission.test.js +16 -8
- package/test/entities/entity.fixtures.js +5 -6
- package/test/entities/entity.test.js +54 -20
- package/test/entities/factory.fixtures.js +11 -10
- package/test/entities/factory.test.js +47 -10
- package/test/entities/set.test.js +1 -1
- package/test/event.test.js +29 -11
- package/test/locator.test.js +10 -4
- package/test/outbox.test.js +49 -15
- package/test/query.test.js +69 -7
- package/test/receiver.fixtures.js +2 -2
- package/test/receiver.test.js +53 -27
- package/test/reflection.test.js +3 -3
- package/test/state.fixtures.js +10 -3
- package/test/state.test.js +77 -14
- package/test/transmission.test.js +25 -12
- package/transpiled/assignment.d.ts +6 -0
- package/transpiled/assignment.js +20 -0
- package/transpiled/assignment.js.map +1 -0
- package/transpiled/call.d.ts +10 -0
- package/transpiled/call.js +52 -0
- package/transpiled/call.js.map +1 -0
- package/transpiled/cascade.d.ts +7 -0
- package/transpiled/cascade.js +28 -0
- package/transpiled/cascade.js.map +1 -0
- package/transpiled/component.d.ts +15 -0
- package/transpiled/component.js +61 -0
- package/transpiled/component.js.map +1 -0
- package/transpiled/composition.d.ts +6 -0
- package/transpiled/composition.js +23 -0
- package/transpiled/composition.js.map +1 -0
- package/transpiled/connector.d.ts +47 -0
- package/transpiled/connector.js +143 -0
- package/transpiled/connector.js.map +1 -0
- package/transpiled/context.d.ts +18 -0
- package/transpiled/context.js +41 -0
- package/transpiled/context.js.map +1 -0
- package/transpiled/contract/contract.d.ts +10 -0
- package/transpiled/contract/contract.js +14 -0
- package/transpiled/contract/contract.js.map +1 -0
- package/transpiled/contract/index.d.ts +2 -0
- package/transpiled/contract/index.js +3 -0
- package/transpiled/contract/index.js.map +1 -0
- package/transpiled/contract/reply.d.ts +7 -0
- package/transpiled/contract/reply.js +48 -0
- package/transpiled/contract/reply.js.map +1 -0
- package/transpiled/contract/request.d.ts +24 -0
- package/transpiled/contract/request.js +59 -0
- package/transpiled/contract/request.js.map +1 -0
- package/transpiled/contract/schemas.d.ts +4 -0
- package/transpiled/contract/schemas.js +36 -0
- package/transpiled/contract/schemas.js.map +1 -0
- package/transpiled/discovery.d.ts +12 -0
- package/transpiled/discovery.js +34 -0
- package/transpiled/discovery.js.map +1 -0
- package/transpiled/effect.d.ts +5 -0
- package/transpiled/effect.js +11 -0
- package/transpiled/effect.js.map +1 -0
- package/transpiled/emission.d.ts +8 -0
- package/transpiled/emission.js +14 -0
- package/transpiled/emission.js.map +1 -0
- package/transpiled/entities/changeset.d.ts +10 -0
- package/transpiled/entities/changeset.js +27 -0
- package/transpiled/entities/changeset.js.map +1 -0
- package/transpiled/entities/entity.d.ts +19 -0
- package/transpiled/entities/entity.js +109 -0
- package/transpiled/entities/entity.js.map +1 -0
- package/transpiled/entities/factory.d.ts +22 -0
- package/transpiled/entities/factory.js +34 -0
- package/transpiled/entities/factory.js.map +1 -0
- package/transpiled/entities/index.d.ts +4 -0
- package/transpiled/entities/index.js +5 -0
- package/transpiled/entities/index.js.map +1 -0
- package/transpiled/entities/newid.d.ts +1 -0
- package/transpiled/entities/newid.js +7 -0
- package/transpiled/entities/newid.js.map +1 -0
- package/transpiled/entities/set.d.ts +10 -0
- package/transpiled/entities/set.js +19 -0
- package/transpiled/entities/set.js.map +1 -0
- package/transpiled/event.d.ts +14 -0
- package/transpiled/event.js +38 -0
- package/transpiled/event.js.map +1 -0
- package/transpiled/exceptions.d.ts +61 -0
- package/transpiled/exceptions.js +93 -0
- package/transpiled/exceptions.js.map +1 -0
- package/transpiled/exposition.d.ts +18 -0
- package/transpiled/exposition.js +18 -0
- package/transpiled/exposition.js.map +1 -0
- package/transpiled/guard.d.ts +7 -0
- package/transpiled/guard.js +12 -0
- package/transpiled/guard.js.map +1 -0
- package/transpiled/index.d.ts +35 -0
- package/transpiled/index.js +29 -0
- package/transpiled/index.js.map +1 -0
- package/transpiled/locator.d.ts +12 -0
- package/transpiled/locator.js +32 -0
- package/transpiled/locator.js.map +1 -0
- package/transpiled/observation.d.ts +5 -0
- package/transpiled/observation.js +12 -0
- package/transpiled/observation.js.map +1 -0
- package/transpiled/operation.d.ts +49 -0
- package/transpiled/operation.js +77 -0
- package/transpiled/operation.js.map +1 -0
- package/transpiled/outbox/index.d.ts +1 -0
- package/transpiled/outbox/index.js +2 -0
- package/transpiled/outbox/index.js.map +1 -0
- package/transpiled/outbox/outbox.d.ts +46 -0
- package/transpiled/outbox/outbox.js +267 -0
- package/transpiled/outbox/outbox.js.map +1 -0
- package/transpiled/query/criteria.d.ts +6 -0
- package/transpiled/query/criteria.js +74 -0
- package/transpiled/query/criteria.js.map +1 -0
- package/transpiled/query/options.d.ts +3 -0
- package/transpiled/query/options.js +27 -0
- package/transpiled/query/options.js.map +1 -0
- package/transpiled/query.d.ts +9 -0
- package/transpiled/query.js +57 -0
- package/transpiled/query.js.map +1 -0
- package/transpiled/receiver.d.ts +20 -0
- package/transpiled/receiver.js +92 -0
- package/transpiled/receiver.js.map +1 -0
- package/transpiled/reflection.d.ts +9 -0
- package/transpiled/reflection.js +13 -0
- package/transpiled/reflection.js.map +1 -0
- package/transpiled/remote.d.ts +10 -0
- package/transpiled/remote.js +12 -0
- package/transpiled/remote.js.map +1 -0
- package/transpiled/state.d.ts +33 -0
- package/transpiled/state.js +126 -0
- package/transpiled/state.js.map +1 -0
- package/transpiled/transition.d.ts +14 -0
- package/transpiled/transition.js +51 -0
- package/transpiled/transition.js.map +1 -0
- package/transpiled/transmission.d.ts +8 -0
- package/transpiled/transmission.js +30 -0
- package/transpiled/transmission.js.map +1 -0
- package/transpiled/types/atomicity.d.ts +56 -0
- package/transpiled/types/atomicity.js +2 -0
- package/transpiled/types/atomicity.js.map +1 -0
- package/transpiled/types/bindings.d.ts +42 -0
- package/transpiled/types/bindings.js +2 -0
- package/transpiled/types/bindings.js.map +1 -0
- package/transpiled/types/bridges.d.ts +38 -0
- package/transpiled/types/bridges.js +2 -0
- package/transpiled/types/bridges.js.map +1 -0
- package/transpiled/types/extensions.d.ts +62 -0
- package/transpiled/types/extensions.js +2 -0
- package/transpiled/types/extensions.js.map +1 -0
- package/transpiled/types/index.d.ts +13 -0
- package/transpiled/types/index.js +8 -0
- package/transpiled/types/index.js.map +1 -0
- package/transpiled/types/message.d.ts +5 -0
- package/transpiled/types/message.js +2 -0
- package/transpiled/types/message.js.map +1 -0
- package/transpiled/types/operations.d.ts +15 -0
- package/transpiled/types/operations.js +2 -0
- package/transpiled/types/operations.js.map +1 -0
- package/transpiled/types/outbox.d.ts +28 -0
- package/transpiled/types/outbox.js +2 -0
- package/transpiled/types/outbox.js.map +1 -0
- package/transpiled/types/receiver.d.ts +9 -0
- package/transpiled/types/receiver.js +2 -0
- package/transpiled/types/receiver.js.map +1 -0
- package/transpiled/types/request.d.ts +55 -0
- package/transpiled/types/request.js +2 -0
- package/transpiled/types/request.js.map +1 -0
- package/transpiled/types/state.d.ts +9 -0
- package/transpiled/types/state.js +2 -0
- package/transpiled/types/state.js.map +1 -0
- package/transpiled/types/storages.d.ts +106 -0
- package/transpiled/types/storages.js +2 -0
- package/transpiled/types/storages.js.map +1 -0
- package/transpiled/unmanaged.d.ts +5 -0
- package/transpiled/unmanaged.js +7 -0
- package/transpiled/unmanaged.js.map +1 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/src/assignment.js +0 -28
- package/src/context.js +0 -57
- package/src/contract/contract.js +0 -18
- package/src/contract/request.js +0 -77
- package/src/contract/schemas/error.yaml +0 -9
- package/src/contract/schemas/index.js +0 -11
- package/src/contract/schemas/query.yaml +0 -43
- package/src/contract/schemas/source.yaml +0 -23
- package/src/effect.js +0 -15
- package/src/entities/changeset.js +0 -36
- package/src/entities/entity.js +0 -119
- package/src/entities/factory.js +0 -40
- package/src/entities/index.js +0 -1
- package/src/event.js +0 -54
- package/src/exposition.js +0 -24
- package/src/guard.js +0 -13
- package/src/observation.js +0 -8
- package/src/operation.js +0 -95
- package/src/query/criteria.js +0 -44
- package/src/query/options.js +0 -37
- package/src/receiver.js +0 -123
- package/src/reflection.js +0 -24
- package/src/remote.js +0 -14
- package/src/state.js +0 -138
- package/src/transition.js +0 -61
- package/src/unmanaged.js +0 -7
- package/types/atomicity.d.ts +0 -79
- package/types/bindings.d.ts +0 -42
- package/types/bridges.ts +0 -33
- package/types/call.d.ts +0 -13
- package/types/component.d.ts +0 -12
- package/types/connector.d.ts +0 -18
- package/types/context.d.ts +0 -24
- package/types/entity.d.ts +0 -46
- package/types/event.d.ts +0 -11
- package/types/exception.d.ts +0 -4
- package/types/extensions.d.ts +0 -73
- package/types/guard.d.ts +0 -5
- package/types/locator.d.ts +0 -13
- package/types/operations.d.ts +0 -8
- package/types/outbox.d.ts +0 -53
- package/types/query.d.ts +0 -17
- package/types/receiver.d.ts +0 -12
- package/types/reflection.d.ts +0 -14
- package/types/remote.d.ts +0 -19
- package/types/state.d.ts +0 -38
- package/types/storages.d.ts +0 -96
- /package/{src/contract/index.js → source/contract/index.ts} +0 -0
- /package/{src/outbox/index.js → source/outbox/index.ts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Exception } from '
|
|
1
|
+
import type { Exception } from '../exceptions.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* What a call asks for. `Entity` is the record it is about, which narrows the projection;
|
|
@@ -6,24 +6,22 @@ import { Exception } from './exception.js'
|
|
|
6
6
|
*/
|
|
7
7
|
export interface Query<Entity = any> {
|
|
8
8
|
id?: string
|
|
9
|
-
ids?:
|
|
9
|
+
ids?: string[]
|
|
10
10
|
criteria?: string
|
|
11
11
|
search?: string
|
|
12
12
|
sample?: number
|
|
13
13
|
omit?: number
|
|
14
14
|
limit?: number
|
|
15
|
-
sort?:
|
|
15
|
+
sort?: string[]
|
|
16
16
|
projection?: Array<string & keyof Entity>
|
|
17
17
|
version?: number
|
|
18
18
|
deleted?: boolean
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
/**
|
|
22
|
-
* Origin of a call. Stamped by the caller, sanitized by the request contract.
|
|
23
|
-
*/
|
|
21
|
+
/** Origin of a call. Stamped by the framework; whoever reads it takes the keys it knows. */
|
|
24
22
|
export type Source =
|
|
25
|
-
| { namespace: string
|
|
26
|
-
| { namespace: string
|
|
23
|
+
| { namespace: string; component: string; operation: string }
|
|
24
|
+
| { namespace: string; component: string; event: string }
|
|
27
25
|
| { service: string }
|
|
28
26
|
|
|
29
27
|
export interface Request<Input = any, Entity = any> {
|
|
@@ -33,7 +31,8 @@ export interface Request<Input = any, Entity = any> {
|
|
|
33
31
|
entity?: Entity
|
|
34
32
|
authentic?: boolean
|
|
35
33
|
task?: boolean
|
|
36
|
-
|
|
34
|
+
/** W3C traceparent */
|
|
35
|
+
telemetry?: string
|
|
37
36
|
source?: Source
|
|
38
37
|
}
|
|
39
38
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** What a commit publishes: the images of one state change. */
|
|
2
|
+
export interface Event<State = object, Trailers = object> {
|
|
3
|
+
/** the pre-image; null when the entity did not exist before */
|
|
4
|
+
origin: State | null
|
|
5
|
+
state: State
|
|
6
|
+
/** out-of-band values an algorithm wrote into `state._trailers`; must be serializable */
|
|
7
|
+
trailers?: Trailers
|
|
8
|
+
input?: object
|
|
9
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { Readable } from 'node:stream'
|
|
2
|
+
import type { Connector } from '../connector.js'
|
|
3
|
+
import type { Locator } from '../locator.js'
|
|
4
|
+
import type { Row, Storage as Outbox } from './outbox.js'
|
|
5
|
+
|
|
6
|
+
/** the RSQL tree `@rsql/parser` produces; a storage translates it into its own dialect */
|
|
7
|
+
export interface Node {
|
|
8
|
+
type: 'LOGIC' | 'COMPARISON' | 'SELECTOR' | 'VALUE'
|
|
9
|
+
left?: Node
|
|
10
|
+
right?: Node
|
|
11
|
+
operator?: string
|
|
12
|
+
selector?: string
|
|
13
|
+
value?: unknown
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** What a storage stores. `id` is the key; the upper-cased names are core's. */
|
|
17
|
+
export interface Record {
|
|
18
|
+
id: string
|
|
19
|
+
VERSION: number
|
|
20
|
+
CREATED?: number
|
|
21
|
+
UPDATED?: number
|
|
22
|
+
/** a tombstone's timestamp; `null` on a live record */
|
|
23
|
+
DELETED?: number | null
|
|
24
|
+
[key: string]: any
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Everything a request query carried that was not a selector. */
|
|
28
|
+
export interface Options {
|
|
29
|
+
omit?: number
|
|
30
|
+
limit?: number
|
|
31
|
+
/** normalised by `query/options.ts` from `'name:asc'` into pairs */
|
|
32
|
+
sort?: Array<[property: string, direction: string]>
|
|
33
|
+
/** always includes `VERSION`, `CREATED`, `UPDATED`, `DELETED` */
|
|
34
|
+
projection?: string[]
|
|
35
|
+
sample?: number
|
|
36
|
+
/** include tombstones; without it an observation answers `null` over one */
|
|
37
|
+
deleted?: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** What core hands a storage, written by `Query.parse`. */
|
|
41
|
+
export interface Query {
|
|
42
|
+
id?: string
|
|
43
|
+
/** many identities at once; `State.objects` inits whichever of them are missing */
|
|
44
|
+
ids?: string[]
|
|
45
|
+
version?: number
|
|
46
|
+
criteria?: Node
|
|
47
|
+
search?: string
|
|
48
|
+
options?: Options
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* What core requires of a storage. Every member but `outbox` is called unguarded, so a
|
|
53
|
+
* storage that leaves one out throws where an operation needs it — a storage may serve
|
|
54
|
+
* only some scopes, and says so by failing rather than by declaring less.
|
|
55
|
+
*/
|
|
56
|
+
export interface Storage extends Connector {
|
|
57
|
+
/** scope `object` */
|
|
58
|
+
get(query: Query): Promise<Record | null>
|
|
59
|
+
|
|
60
|
+
/** scope `objects` */
|
|
61
|
+
find(query: Query): Promise<Record[]>
|
|
62
|
+
|
|
63
|
+
/** scope `stream` */
|
|
64
|
+
stream(query?: Query): Promise<Readable>
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* A transition's commit. `false` is a lost compare-and-swap, not an error. Where `row` is
|
|
68
|
+
* given, it is committed in the same transaction as the record or not at all.
|
|
69
|
+
*/
|
|
70
|
+
store(record: Record, row?: Row): Promise<boolean>
|
|
71
|
+
|
|
72
|
+
/** a transition over `objects` */
|
|
73
|
+
massStore(records: Record[], rows?: Row[]): Promise<boolean>
|
|
74
|
+
|
|
75
|
+
/** an assignment; `null` where the query matched nothing */
|
|
76
|
+
upsert(query: Query, changeset: object, row?: Row): Promise<Record | null>
|
|
77
|
+
|
|
78
|
+
/** get-or-create, in one indivisible step */
|
|
79
|
+
ensure(
|
|
80
|
+
query: Query | undefined,
|
|
81
|
+
properties: object,
|
|
82
|
+
record: Record,
|
|
83
|
+
row?: Row
|
|
84
|
+
): Promise<Record>
|
|
85
|
+
|
|
86
|
+
/** the driver's own handle, which an unmanaged operation is given as its state */
|
|
87
|
+
readonly raw: unknown
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Present only where a row can be committed atomically with the entity. Its absence is
|
|
91
|
+
* what makes the runtime publish inline, so a storage that cannot do this must not offer
|
|
92
|
+
* it: a row written outside the transaction would be a second write with a crash window
|
|
93
|
+
* in front of it, which is the defect the outbox exists to close.
|
|
94
|
+
*/
|
|
95
|
+
readonly outbox?: Outbox
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Whether this storage applies `entity.migrations`. Absent is what a storage that does not
|
|
99
|
+
* says, and a component declaring migrations against one is refused at boot rather than
|
|
100
|
+
* starting with a structure nothing has made.
|
|
101
|
+
*/
|
|
102
|
+
readonly migrates?: boolean
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The subset of a component's entity declaration a storage reads. Structural, so that core
|
|
107
|
+
* names no type of `@toa.io/norm`, which depends on core.
|
|
108
|
+
*/
|
|
109
|
+
export interface Entity {
|
|
110
|
+
associated?: boolean
|
|
111
|
+
custom?: boolean
|
|
112
|
+
/** in the order they are applied; what a step is belongs to the storage that reads it */
|
|
113
|
+
migrations?: Migration[]
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** One file of a component's `migrations` directory, named after it. */
|
|
117
|
+
export interface Migration {
|
|
118
|
+
id: string
|
|
119
|
+
steps: unknown[]
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface StorageOptions {
|
|
123
|
+
/** whether the component publishes anything, and so needs a place to commit a row */
|
|
124
|
+
outbox?: boolean
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface Factory {
|
|
128
|
+
storage(locator: Locator, entity: Entity, options?: StorageOptions): Storage
|
|
129
|
+
}
|
package/test/call.fixtures.js
CHANGED
|
@@ -4,7 +4,9 @@ import { generate } from 'randomstring'
|
|
|
4
4
|
|
|
5
5
|
// noinspection JSCheckFunctionSignatures
|
|
6
6
|
export const transmission = {
|
|
7
|
-
request: mock.fn((request) => ({
|
|
7
|
+
request: mock.fn((request) => ({
|
|
8
|
+
[request.invalid ? 'exception' : 'output']: generate()
|
|
9
|
+
})),
|
|
8
10
|
link: mock.fn()
|
|
9
11
|
}
|
|
10
12
|
|
package/test/call.test.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { it, beforeEach
|
|
1
|
+
import { it, beforeEach } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
import { isDeepStrictEqual } from 'node:util'
|
|
4
4
|
|
|
5
5
|
import * as fixtures from './call.fixtures.js'
|
|
6
|
-
import { Call } from '../
|
|
6
|
+
import { Call } from '../source/call.js'
|
|
7
7
|
|
|
8
8
|
let call
|
|
9
9
|
|
|
@@ -14,7 +14,13 @@ beforeEach(() => {
|
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
it('should depend on transmission', () => {
|
|
17
|
-
assert.ok(
|
|
17
|
+
assert.ok(
|
|
18
|
+
((invocation) =>
|
|
19
|
+
invocation.arguments.length === 1 &&
|
|
20
|
+
isDeepStrictEqual(invocation.arguments[0], call))(
|
|
21
|
+
fixtures.transmission.link.mock.calls.at(-1) ?? { arguments: [] }
|
|
22
|
+
)
|
|
23
|
+
)
|
|
18
24
|
})
|
|
19
25
|
|
|
20
26
|
it('should call transmission', async () => {
|
|
@@ -22,7 +28,13 @@ it('should call transmission', async () => {
|
|
|
22
28
|
|
|
23
29
|
await call.invoke(request)
|
|
24
30
|
|
|
25
|
-
assert.ok(
|
|
31
|
+
assert.ok(
|
|
32
|
+
fixtures.transmission.request.mock.calls.some(
|
|
33
|
+
(invocation) =>
|
|
34
|
+
invocation.arguments.length === 1 &&
|
|
35
|
+
isDeepStrictEqual(invocation.arguments[0], request)
|
|
36
|
+
)
|
|
37
|
+
)
|
|
26
38
|
})
|
|
27
39
|
|
|
28
40
|
it('should fit request', async () => {
|
|
@@ -30,7 +42,13 @@ it('should fit request', async () => {
|
|
|
30
42
|
|
|
31
43
|
await call.invoke(request)
|
|
32
44
|
|
|
33
|
-
assert.ok(
|
|
45
|
+
assert.ok(
|
|
46
|
+
((invocation) =>
|
|
47
|
+
invocation.arguments.length === 1 &&
|
|
48
|
+
isDeepStrictEqual(invocation.arguments[0], request))(
|
|
49
|
+
fixtures.contract.fit.mock.calls.at(-1) ?? { arguments: [] }
|
|
50
|
+
)
|
|
51
|
+
)
|
|
34
52
|
})
|
|
35
53
|
|
|
36
54
|
it('should return reply', async () => {
|
|
@@ -44,10 +62,13 @@ it('should return reply', async () => {
|
|
|
44
62
|
it('should throw received exceptions', async () => {
|
|
45
63
|
const request = fixtures.request().bad
|
|
46
64
|
|
|
47
|
-
await assert.rejects(call.invoke(request), (error) => {
|
|
65
|
+
await assert.rejects(call.invoke(request), (error) => {
|
|
66
|
+
assert.notStrictEqual(error, undefined)
|
|
67
|
+
return true
|
|
68
|
+
})
|
|
48
69
|
})
|
|
49
70
|
|
|
50
|
-
function resetCalls
|
|
71
|
+
function resetCalls(target = [assert, fixtures], seen = new Set()) {
|
|
51
72
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
52
73
|
|
|
53
74
|
seen.add(target)
|
package/test/component.test.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { describe, it, beforeEach
|
|
1
|
+
import { describe, it, beforeEach } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
import { isDeepStrictEqual } from 'node:util'
|
|
4
4
|
|
|
5
|
-
import { Component } from '../
|
|
6
|
-
import { codes } from '../src/exceptions.js'
|
|
5
|
+
import { Component } from '../source/component.js'
|
|
7
6
|
import * as fixtures from './component.fixtures.js'
|
|
8
7
|
import { AssertionError } from 'node:assert'
|
|
9
8
|
|
|
@@ -31,7 +30,13 @@ describe('Invocations', () => {
|
|
|
31
30
|
const query = { test: Math.random() }
|
|
32
31
|
await component.invoke(name, { input, query })
|
|
33
32
|
|
|
34
|
-
assert.ok(
|
|
33
|
+
assert.ok(
|
|
34
|
+
invocation.invoke.mock.calls.some(
|
|
35
|
+
(call) =>
|
|
36
|
+
call.arguments.length === 1 &&
|
|
37
|
+
isDeepStrictEqual(call.arguments[0], { input, query })
|
|
38
|
+
)
|
|
39
|
+
)
|
|
35
40
|
})
|
|
36
41
|
|
|
37
42
|
it('should return io', async () => {
|
|
@@ -41,7 +46,7 @@ describe('Invocations', () => {
|
|
|
41
46
|
})
|
|
42
47
|
})
|
|
43
48
|
|
|
44
|
-
function resetCalls
|
|
49
|
+
function resetCalls(target = [assert, fixtures], seen = new Set()) {
|
|
45
50
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
46
51
|
|
|
47
52
|
seen.add(target)
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
import { random, timeout } from '@toa.io/generic'
|
|
2
|
-
import { Connector } from '../
|
|
2
|
+
import { Connector } from '../source/connector.js'
|
|
3
3
|
|
|
4
4
|
export class TestConnector extends Connector {
|
|
5
5
|
#label
|
|
6
6
|
#seq
|
|
7
7
|
|
|
8
|
-
constructor
|
|
8
|
+
constructor(label, seq) {
|
|
9
9
|
super()
|
|
10
10
|
|
|
11
11
|
this.#seq = seq
|
|
12
12
|
this.#label = label
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
async open
|
|
15
|
+
async open() {
|
|
16
16
|
await timeout(random(10))
|
|
17
17
|
this.#seq.push(`+${this.#label}`)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
async close
|
|
20
|
+
async close() {
|
|
21
21
|
await timeout(random(10))
|
|
22
22
|
this.#seq.push(`-${this.#label}`)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
async dispose
|
|
25
|
+
async dispose() {
|
|
26
26
|
this.#seq.push(`*${this.#label}`)
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export class FailingConnector extends Connector {
|
|
31
|
-
async open
|
|
31
|
+
async open() {
|
|
32
32
|
await timeout(random(10))
|
|
33
33
|
throw new Error('FailingConnector')
|
|
34
34
|
}
|
|
@@ -36,7 +36,7 @@ export class FailingConnector extends Connector {
|
|
|
36
36
|
|
|
37
37
|
/** Stands for a connector waiting for something that never arrives. */
|
|
38
38
|
export class StuckConnector extends Connector {
|
|
39
|
-
async open
|
|
39
|
+
async open() {
|
|
40
40
|
return new Promise(() => undefined)
|
|
41
41
|
}
|
|
42
42
|
}
|
package/test/connector.test.js
CHANGED
|
@@ -87,7 +87,10 @@ describe('dependencies', () => {
|
|
|
87
87
|
})
|
|
88
88
|
|
|
89
89
|
it('should throw on empty array', async () => {
|
|
90
|
-
assert.throws(
|
|
90
|
+
assert.throws(
|
|
91
|
+
() => a.depends([]),
|
|
92
|
+
(error) => /must not be empty/.test(error.message)
|
|
93
|
+
)
|
|
91
94
|
})
|
|
92
95
|
|
|
93
96
|
it('should await 2-way dependencies', async () => {
|
|
@@ -143,7 +146,17 @@ describe('dependencies', () => {
|
|
|
143
146
|
|
|
144
147
|
await b.disconnect()
|
|
145
148
|
|
|
146
|
-
assert.deepStrictEqual(sequence, [
|
|
149
|
+
assert.deepStrictEqual(sequence, [
|
|
150
|
+
'+c',
|
|
151
|
+
'+a',
|
|
152
|
+
'+b',
|
|
153
|
+
'-a',
|
|
154
|
+
'*a',
|
|
155
|
+
'-b',
|
|
156
|
+
'-c',
|
|
157
|
+
'*c',
|
|
158
|
+
'*b'
|
|
159
|
+
])
|
|
147
160
|
})
|
|
148
161
|
|
|
149
162
|
it('should throw if depends not on Connector', async () => {
|
package/test/context.fixtures.js
CHANGED
package/test/context.test.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { describe, it, beforeEach
|
|
1
|
+
import { describe, it, beforeEach } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
|
|
4
4
|
import * as fixtures from './context.fixtures.js'
|
|
5
|
-
import { Context } from '../
|
|
5
|
+
import { Context } from '../source/context.js'
|
|
6
6
|
|
|
7
|
-
/** @type {toa.core.Context} */
|
|
7
|
+
/** @type {import('@toa.io/core').Context} */
|
|
8
8
|
let context
|
|
9
9
|
|
|
10
10
|
beforeEach(() => {
|
|
@@ -29,7 +29,7 @@ describe('call', () => {
|
|
|
29
29
|
})
|
|
30
30
|
})
|
|
31
31
|
|
|
32
|
-
function resetCalls
|
|
32
|
+
function resetCalls(target = [assert, fixtures], seen = new Set()) {
|
|
33
33
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
34
34
|
|
|
35
35
|
seen.add(target)
|
|
@@ -4,7 +4,7 @@ import { isDeepStrictEqual } from 'node:util'
|
|
|
4
4
|
|
|
5
5
|
import { generate } from 'randomstring'
|
|
6
6
|
|
|
7
|
-
import { Contract } from '../../
|
|
7
|
+
import { Contract } from '../../source/contract/contract.js'
|
|
8
8
|
import * as fixtures from './contract.fixtures.js'
|
|
9
9
|
|
|
10
10
|
let contract
|
|
@@ -18,7 +18,11 @@ it('should fit value', () => {
|
|
|
18
18
|
|
|
19
19
|
contract.fit(value)
|
|
20
20
|
|
|
21
|
-
assert.ok(
|
|
21
|
+
assert.ok(
|
|
22
|
+
fixtures.schema.fit.mock.calls.some(
|
|
23
|
+
(call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], value)
|
|
24
|
+
)
|
|
25
|
+
)
|
|
22
26
|
})
|
|
23
27
|
|
|
24
28
|
it('should throw on invalid value', () => {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { mock } from 'node:test'
|
|
2
2
|
|
|
3
3
|
import { generate } from 'randomstring'
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import { resolve } from 'path'
|
|
4
|
+
|
|
5
|
+
import { query as querySchema } from '../../source/contract/schemas.js'
|
|
7
6
|
|
|
8
7
|
// noinspection JSCheckFunctionSignatures
|
|
9
8
|
export const schema = {
|
|
@@ -21,7 +20,7 @@ export const schemas = {
|
|
|
21
20
|
type: 'object',
|
|
22
21
|
properties: {
|
|
23
22
|
input: { type: 'null' },
|
|
24
|
-
query:
|
|
23
|
+
query: querySchema,
|
|
25
24
|
authentic: { type: 'boolean' }
|
|
26
25
|
},
|
|
27
26
|
additionalProperties: true
|
|
@@ -6,8 +6,8 @@ import { isDeepStrictEqual } from 'node:util'
|
|
|
6
6
|
import clone from 'clone-deep'
|
|
7
7
|
import { generate } from 'randomstring'
|
|
8
8
|
|
|
9
|
-
import { Request } from '../../
|
|
10
|
-
import { Contract } from '../../
|
|
9
|
+
import { Request } from '../../source/contract/request.js'
|
|
10
|
+
import { Contract } from '../../source/contract/contract.js'
|
|
11
11
|
import * as fixtures from './contract.fixtures.js'
|
|
12
12
|
|
|
13
13
|
// the base is real; what it was constructed with and told to fit is observable
|
|
@@ -22,7 +22,7 @@ beforeEach(() => {
|
|
|
22
22
|
contract = new Request(fixtures.schema, {})
|
|
23
23
|
})
|
|
24
24
|
|
|
25
|
-
const dummy = {
|
|
25
|
+
const dummy = { properties: {} }
|
|
26
26
|
|
|
27
27
|
it('should extend Conditions', () => {
|
|
28
28
|
assert.ok(contract instanceof Contract)
|
|
@@ -34,8 +34,11 @@ it('should fit request', () => {
|
|
|
34
34
|
|
|
35
35
|
contract.fit(request)
|
|
36
36
|
|
|
37
|
-
assert.ok(
|
|
38
|
-
|
|
37
|
+
assert.ok(
|
|
38
|
+
fit.mock.calls.some(
|
|
39
|
+
(call) => call.this === contract && isDeepStrictEqual(call.arguments[0], request)
|
|
40
|
+
)
|
|
41
|
+
)
|
|
39
42
|
})
|
|
40
43
|
|
|
41
44
|
describe('schema', () => {
|
|
@@ -70,21 +73,45 @@ describe('schema', () => {
|
|
|
70
73
|
|
|
71
74
|
it('should require query if declaration.query is true', () => {
|
|
72
75
|
schema.required = ['query']
|
|
73
|
-
assert.ok(
|
|
76
|
+
assert.ok(
|
|
77
|
+
['query'].every((item) =>
|
|
78
|
+
Request.schema({ query: true }, dummy).required.some((candidate) =>
|
|
79
|
+
isDeepStrictEqual(candidate, item)
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
)
|
|
74
83
|
})
|
|
75
84
|
|
|
76
85
|
it('should forbid projection for non observations', () => {
|
|
77
|
-
assert.strictEqual(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
assert.strictEqual(
|
|
87
|
+
Request.schema({ type: 'transition' }, dummy).properties.query.properties
|
|
88
|
+
.projection,
|
|
89
|
+
undefined
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
assert.strictEqual(
|
|
93
|
+
Request.schema({ type: 'assignment' }, dummy).properties.query.properties
|
|
94
|
+
.projection,
|
|
95
|
+
undefined
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
assert.notStrictEqual(
|
|
99
|
+
Request.schema({ type: 'observation' }, dummy).properties.query.properties
|
|
100
|
+
.projection,
|
|
101
|
+
undefined
|
|
102
|
+
)
|
|
82
103
|
})
|
|
83
104
|
|
|
84
105
|
it('should forbid version for observations', () => {
|
|
85
|
-
assert.notStrictEqual(
|
|
86
|
-
|
|
87
|
-
|
|
106
|
+
assert.notStrictEqual(
|
|
107
|
+
Request.schema({ type: 'transition' }, dummy).properties.query.properties.version,
|
|
108
|
+
undefined
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
assert.strictEqual(
|
|
112
|
+
Request.schema({ type: 'observation' }, dummy).properties.query.properties.version,
|
|
113
|
+
undefined
|
|
114
|
+
)
|
|
88
115
|
})
|
|
89
116
|
|
|
90
117
|
it('should allow omit, limit only for set observations', () => {
|
|
@@ -94,18 +121,24 @@ describe('schema', () => {
|
|
|
94
121
|
assert.strictEqual(transition.omit, undefined)
|
|
95
122
|
assert.strictEqual(transition.limit, undefined)
|
|
96
123
|
|
|
97
|
-
const object = Request.schema(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
124
|
+
const object = Request.schema(
|
|
125
|
+
{
|
|
126
|
+
type: 'observation',
|
|
127
|
+
scope: 'object'
|
|
128
|
+
},
|
|
129
|
+
dummy
|
|
130
|
+
).properties.query.properties
|
|
101
131
|
|
|
102
132
|
assert.strictEqual(object.omit, undefined)
|
|
103
133
|
assert.strictEqual(object.limit, undefined)
|
|
104
134
|
|
|
105
|
-
const objects = Request.schema(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
135
|
+
const objects = Request.schema(
|
|
136
|
+
{
|
|
137
|
+
type: 'observation',
|
|
138
|
+
scope: 'objects'
|
|
139
|
+
},
|
|
140
|
+
dummy
|
|
141
|
+
).properties.query.properties
|
|
109
142
|
|
|
110
143
|
assert.notStrictEqual(objects.omit, undefined)
|
|
111
144
|
assert.notStrictEqual(objects.limit, undefined)
|
|
@@ -113,16 +146,13 @@ describe('schema', () => {
|
|
|
113
146
|
})
|
|
114
147
|
|
|
115
148
|
describe('source', () => {
|
|
116
|
-
|
|
117
|
-
|
|
118
149
|
const compile = (definition, entity) =>
|
|
119
|
-
schemas.schema(Request.schema(definition, entity)
|
|
150
|
+
schemas.schema(Request.schema(definition, entity))
|
|
120
151
|
|
|
121
|
-
it('should
|
|
152
|
+
it('should not hold source to a schema', () => {
|
|
122
153
|
const schema = Request.schema({}, dummy)
|
|
123
154
|
|
|
124
|
-
assert.
|
|
125
|
-
assert.deepStrictEqual(schema.properties.source.additionalProperties, false)
|
|
155
|
+
assert.strictEqual(schema.properties.source, undefined)
|
|
126
156
|
})
|
|
127
157
|
|
|
128
158
|
it('should pass known source variants', () => {
|
|
@@ -140,18 +170,22 @@ describe('source', () => {
|
|
|
140
170
|
}
|
|
141
171
|
})
|
|
142
172
|
|
|
143
|
-
//
|
|
144
|
-
//
|
|
145
|
-
it('should
|
|
173
|
+
// whatever a peer puts beside the keys this release knows travels through: what reads
|
|
174
|
+
// `source` takes the keys it knows, and the contract does not fail a call over the rest
|
|
175
|
+
it('should pass a source a peer added to', () => {
|
|
146
176
|
const schema = compile({}, undefined)
|
|
147
|
-
const request = {
|
|
177
|
+
const request = {
|
|
178
|
+
input: null,
|
|
179
|
+
query: null,
|
|
180
|
+
source: { service: 'exposition', mystery: 'x' }
|
|
181
|
+
}
|
|
148
182
|
|
|
149
183
|
assert.deepStrictEqual(schema.fit(request), null)
|
|
150
|
-
assert.deepStrictEqual(request.source, { service: 'exposition' })
|
|
184
|
+
assert.deepStrictEqual(request.source, { service: 'exposition', mystery: 'x' })
|
|
151
185
|
})
|
|
152
186
|
})
|
|
153
187
|
|
|
154
|
-
function resetCalls
|
|
188
|
+
function resetCalls(target = [assert, clone, fixtures, dummy], seen = new Set()) {
|
|
155
189
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
156
190
|
|
|
157
191
|
seen.add(target)
|
package/test/discovery.test.js
CHANGED
|
@@ -3,8 +3,8 @@ import assert from 'node:assert/strict'
|
|
|
3
3
|
import { isDeepStrictEqual } from 'node:util'
|
|
4
4
|
|
|
5
5
|
import { console } from 'openspan'
|
|
6
|
-
import { Connector } from '../
|
|
7
|
-
import { Discovery } from '../
|
|
6
|
+
import { Connector } from '../source/connector.js'
|
|
7
|
+
import { Discovery } from '../source/discovery.js'
|
|
8
8
|
|
|
9
9
|
class Lookup extends Connector {
|
|
10
10
|
invoke = mock.fn(async () => ({ operations: {} }))
|
|
@@ -60,5 +60,12 @@ it('should keep warning while a lookup is unanswered', async () => {
|
|
|
60
60
|
|
|
61
61
|
assert.strictEqual(warn.mock.callCount(), 2)
|
|
62
62
|
|
|
63
|
-
assert.ok(
|
|
63
|
+
assert.ok(
|
|
64
|
+
((call) =>
|
|
65
|
+
call.arguments.length === 2 &&
|
|
66
|
+
isDeepStrictEqual(call.arguments[0], 'Waiting for lookup response') &&
|
|
67
|
+
isDeepStrictEqual(call.arguments[1], { component: locator.id, waiting: 10 }))(
|
|
68
|
+
warn.mock.calls.at(-1) ?? { arguments: [] }
|
|
69
|
+
)
|
|
70
|
+
)
|
|
64
71
|
})
|