@toa.io/core 1.0.0-alpha.29 → 1.0.0-alpha.291
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 +35 -0
- package/package.json +22 -12
- package/source/assignment.ts +27 -0
- package/source/call.ts +63 -0
- package/source/cascade.ts +32 -0
- package/source/component.ts +83 -0
- package/source/composition.ts +27 -0
- package/source/connector.ts +217 -0
- package/source/context.ts +68 -0
- package/source/contract/contract.ts +23 -0
- package/source/contract/index.ts +2 -0
- package/source/contract/reply.ts +56 -0
- package/source/contract/request.ts +140 -0
- package/source/contract/schemas.ts +39 -0
- package/source/discovery.ts +53 -0
- package/source/effect.ts +14 -0
- package/source/emission.ts +21 -0
- 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/source/entities/newid.ts +9 -0
- package/source/entities/set.ts +27 -0
- package/source/event.ts +57 -0
- package/source/exceptions.ts +133 -0
- package/source/exposition.ts +33 -0
- package/source/guard.ts +16 -0
- package/source/index.ts +36 -0
- package/source/locator.ts +37 -0
- package/source/observation.ts +16 -0
- package/source/operation.ts +139 -0
- package/source/outbox/index.ts +1 -0
- package/source/outbox/outbox.ts +341 -0
- package/source/query/criteria.ts +90 -0
- package/source/query/options.ts +35 -0
- package/source/query.ts +67 -0
- 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/source/transmission.ts +38 -0
- 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/source/types/index.ts +14 -0
- package/{types/message.d.ts → source/types/message.ts} +2 -0
- package/source/types/operations.ts +31 -0
- package/source/types/outbox.ts +35 -0
- package/source/types/receiver.ts +10 -0
- package/source/types/request.ts +54 -0
- package/source/types/state.ts +9 -0
- package/source/types/storages.ts +134 -0
- package/source/unmanaged.ts +8 -0
- package/test/call.fixtures.js +10 -12
- package/test/call.test.js +42 -9
- package/test/component.fixtures.js +5 -8
- package/test/component.test.js +27 -10
- package/test/connector.fixtures.js +29 -13
- package/test/connector.test.js +128 -38
- package/test/context.fixtures.js +8 -12
- package/test/context.test.js +19 -8
- package/test/contract/conditions.test.js +15 -9
- package/test/contract/contract.fixtures.js +11 -16
- package/test/contract/request.test.js +130 -46
- package/test/discovery.test.js +71 -0
- package/test/emission.fixtures.js +6 -10
- package/test/emission.test.js +37 -12
- package/test/entities/entity.fixtures.js +11 -16
- package/test/entities/entity.test.js +105 -50
- package/test/entities/factory.fixtures.js +26 -13
- package/test/entities/factory.test.js +68 -17
- package/test/entities/set.fixtures.js +6 -8
- package/test/entities/set.test.js +6 -5
- package/test/event.fixtures.js +9 -14
- package/test/event.test.js +78 -34
- package/test/locator.test.js +32 -25
- package/test/outbox.test.js +202 -0
- package/test/query.fixtures.js +1 -5
- package/test/query.test.js +111 -14
- package/test/receiver.fixtures.js +9 -12
- package/test/receiver.test.js +80 -31
- package/test/reflection.test.js +9 -8
- package/test/state.fixtures.js +33 -31
- package/test/state.test.js +135 -19
- package/test/transmission.fixtures.js +4 -6
- package/test/transmission.test.js +47 -16
- 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 +185 -0
- package/transpiled/connector.js.map +1 -0
- package/transpiled/context.d.ts +18 -0
- package/transpiled/context.js +42 -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 +29 -0
- package/transpiled/contract/request.js +103 -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 +78 -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 +268 -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 +111 -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 -31
- package/src/call.js +0 -42
- package/src/cascade.js +0 -36
- package/src/component.js +0 -41
- package/src/composition.js +0 -25
- package/src/connector.js +0 -183
- package/src/context.js +0 -55
- package/src/contract/conditions.js +0 -21
- package/src/contract/index.js +0 -7
- package/src/contract/reply.js +0 -25
- package/src/contract/request.js +0 -67
- package/src/contract/schemas/error.yaml +0 -9
- package/src/contract/schemas/index.js +0 -7
- package/src/contract/schemas/query.yaml +0 -30
- package/src/discovery.js +0 -44
- package/src/emission.js +0 -23
- package/src/entities/changeset.js +0 -43
- package/src/entities/entity.js +0 -73
- package/src/entities/factory.js +0 -33
- package/src/entities/index.js +0 -5
- package/src/entities/set.js +0 -15
- package/src/event.js +0 -40
- package/src/exceptions.js +0 -100
- package/src/exposition.js +0 -27
- package/src/index.js +0 -47
- package/src/locator.js +0 -54
- package/src/observation.js +0 -20
- package/src/operation.js +0 -69
- package/src/query/criteria.js +0 -41
- package/src/query/options.js +0 -40
- package/src/query.js +0 -41
- package/src/receiver.js +0 -65
- package/src/reflection.js +0 -28
- package/src/remote.js +0 -17
- package/src/state.js +0 -99
- package/src/transition.js +0 -73
- package/src/transmission.js +0 -33
- package/types/bindings.d.ts +0 -40
- package/types/bridges.ts +0 -30
- package/types/component.d.ts +0 -9
- package/types/connector.d.ts +0 -18
- package/types/context.d.ts +0 -21
- 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 -29
- package/types/index.ts +0 -14
- package/types/locator.d.ts +0 -13
- package/types/operations.d.ts +0 -2
- package/types/query.d.ts +0 -15
- package/types/receiver.d.ts +0 -12
- package/types/reflection.d.ts +0 -14
- package/types/request.d.ts +0 -23
- package/types/state.d.ts +0 -35
- package/types/storages.d.ts +0 -71
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Exception } from '../exceptions.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What a call asks for. `Entity` is the record it is about, which narrows the projection;
|
|
5
|
+
* left out, any name is accepted.
|
|
6
|
+
*/
|
|
7
|
+
export interface Query<Entity = any> {
|
|
8
|
+
id?: string
|
|
9
|
+
ids?: string[]
|
|
10
|
+
criteria?: string
|
|
11
|
+
search?: string
|
|
12
|
+
sample?: number
|
|
13
|
+
omit?: number
|
|
14
|
+
limit?: number
|
|
15
|
+
sort?: string[]
|
|
16
|
+
projection?: Array<string & keyof Entity>
|
|
17
|
+
version?: number
|
|
18
|
+
deleted?: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Origin of a call. Stamped by the framework; whoever reads it takes the keys it knows. */
|
|
22
|
+
export type Source =
|
|
23
|
+
| { namespace: string; component: string; operation: string }
|
|
24
|
+
| { namespace: string; component: string; event: string }
|
|
25
|
+
| { service: string }
|
|
26
|
+
|
|
27
|
+
export interface Request<Input = any, Entity = any> {
|
|
28
|
+
input?: Input
|
|
29
|
+
query?: Query<Entity>
|
|
30
|
+
/** What the operation acquires, where the caller supplies it rather than the storage. */
|
|
31
|
+
entity?: Entity
|
|
32
|
+
authentic?: boolean
|
|
33
|
+
task?: boolean
|
|
34
|
+
/** W3C traceparent */
|
|
35
|
+
telemetry?: string
|
|
36
|
+
source?: Source
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* An error an operation declares and returns. A call resolves to it rather than throwing:
|
|
41
|
+
* only an exception is thrown.
|
|
42
|
+
*/
|
|
43
|
+
export interface RemoteError<Code extends string = string> extends Error {
|
|
44
|
+
code: Code
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** What an operation returns where it may refuse: the value, or the error it refused with. */
|
|
48
|
+
export type Maybe<T> = T | Error
|
|
49
|
+
|
|
50
|
+
export interface Reply {
|
|
51
|
+
output?: any
|
|
52
|
+
error?: object
|
|
53
|
+
exception?: Exception
|
|
54
|
+
}
|
|
@@ -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,134 @@
|
|
|
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
|
+
/**
|
|
117
|
+
* One file of a `migrations` directory, named after it — the component's own, or a prototype's,
|
|
118
|
+
* which every descendant applies to its collection ahead of its own.
|
|
119
|
+
*/
|
|
120
|
+
export interface Migration {
|
|
121
|
+
id: string
|
|
122
|
+
steps: unknown[]
|
|
123
|
+
/** the prototype it is inherited from; absent on the component's own */
|
|
124
|
+
prototype?: string
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface StorageOptions {
|
|
128
|
+
/** whether the component publishes anything, and so needs a place to commit a row */
|
|
129
|
+
outbox?: boolean
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface Factory {
|
|
133
|
+
storage(locator: Locator, entity: Entity, options?: StorageOptions): Storage
|
|
134
|
+
}
|
package/test/call.fixtures.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
import { mock } from 'node:test'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import { generate } from 'randomstring'
|
|
4
4
|
|
|
5
5
|
// noinspection JSCheckFunctionSignatures
|
|
6
|
-
const transmission = {
|
|
7
|
-
request:
|
|
8
|
-
|
|
6
|
+
export const transmission = {
|
|
7
|
+
request: mock.fn((request) => ({
|
|
8
|
+
[request.invalid ? 'exception' : 'output']: generate()
|
|
9
|
+
})),
|
|
10
|
+
link: mock.fn()
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
const contract = {
|
|
12
|
-
fit:
|
|
13
|
+
export const contract = {
|
|
14
|
+
fit: mock.fn(() => null)
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
const request = () => ({
|
|
17
|
+
export const request = () => ({
|
|
16
18
|
ok: {
|
|
17
19
|
input: { [generate()]: generate() },
|
|
18
20
|
query: { [generate()]: generate() }
|
|
@@ -21,7 +23,3 @@ const request = () => ({
|
|
|
21
23
|
invalid: true
|
|
22
24
|
}
|
|
23
25
|
})
|
|
24
|
-
|
|
25
|
-
exports.transmission = transmission
|
|
26
|
-
exports.contract = contract
|
|
27
|
-
exports.request = request
|
package/test/call.test.js
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
import { it, beforeEach } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { isDeepStrictEqual } from 'node:util'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
import * as fixtures from './call.fixtures.js'
|
|
6
|
+
import { Call } from '../source/call.js'
|
|
5
7
|
|
|
6
8
|
let call
|
|
7
9
|
|
|
8
10
|
beforeEach(() => {
|
|
9
|
-
|
|
11
|
+
resetCalls()
|
|
10
12
|
|
|
11
13
|
call = new Call(fixtures.transmission, fixtures.contract)
|
|
12
14
|
})
|
|
13
15
|
|
|
14
16
|
it('should depend on transmission', () => {
|
|
15
|
-
|
|
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
|
+
)
|
|
16
24
|
})
|
|
17
25
|
|
|
18
26
|
it('should call transmission', async () => {
|
|
@@ -20,7 +28,13 @@ it('should call transmission', async () => {
|
|
|
20
28
|
|
|
21
29
|
await call.invoke(request)
|
|
22
30
|
|
|
23
|
-
|
|
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
|
+
)
|
|
24
38
|
})
|
|
25
39
|
|
|
26
40
|
it('should fit request', async () => {
|
|
@@ -28,7 +42,13 @@ it('should fit request', async () => {
|
|
|
28
42
|
|
|
29
43
|
await call.invoke(request)
|
|
30
44
|
|
|
31
|
-
|
|
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
|
+
)
|
|
32
52
|
})
|
|
33
53
|
|
|
34
54
|
it('should return reply', async () => {
|
|
@@ -36,11 +56,24 @@ it('should return reply', async () => {
|
|
|
36
56
|
|
|
37
57
|
const reply = await call.invoke(request)
|
|
38
58
|
|
|
39
|
-
|
|
59
|
+
assert.deepStrictEqual(reply, fixtures.transmission.request.mock.calls[0].result.output)
|
|
40
60
|
})
|
|
41
61
|
|
|
42
62
|
it('should throw received exceptions', async () => {
|
|
43
63
|
const request = fixtures.request().bad
|
|
44
64
|
|
|
45
|
-
await
|
|
65
|
+
await assert.rejects(call.invoke(request), (error) => {
|
|
66
|
+
assert.notStrictEqual(error, undefined)
|
|
67
|
+
return true
|
|
68
|
+
})
|
|
46
69
|
})
|
|
70
|
+
|
|
71
|
+
function resetCalls(target = [assert, fixtures], seen = new Set()) {
|
|
72
|
+
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
73
|
+
|
|
74
|
+
seen.add(target)
|
|
75
|
+
|
|
76
|
+
for (const value of Object.values(target))
|
|
77
|
+
if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
|
|
78
|
+
else resetCalls(value, seen)
|
|
79
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { mock } from 'node:test'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import randomstring from 'randomstring'
|
|
4
4
|
|
|
5
|
-
const invocation = () =>
|
|
5
|
+
const invocation = () => mock.fn(() => randomstring.generate())
|
|
6
6
|
|
|
7
|
-
const invocations = {
|
|
7
|
+
export const invocations = {
|
|
8
8
|
foo: {
|
|
9
9
|
invoke: invocation('foo'),
|
|
10
10
|
link: () => null
|
|
@@ -15,7 +15,4 @@ const invocations = {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const locator = {}
|
|
19
|
-
|
|
20
|
-
exports.invocations = invocations
|
|
21
|
-
exports.locator = locator
|
|
18
|
+
export const locator = {}
|
package/test/component.test.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { describe, it, beforeEach } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { isDeepStrictEqual } from 'node:util'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
import { Component } from '../source/component.js'
|
|
6
|
+
import * as fixtures from './component.fixtures.js'
|
|
7
|
+
import { AssertionError } from 'node:assert'
|
|
6
8
|
|
|
7
9
|
describe('Invocations', () => {
|
|
8
10
|
const name = ['foo', 'bar'][Math.floor(2 * Math.random())]
|
|
@@ -10,18 +12,17 @@ describe('Invocations', () => {
|
|
|
10
12
|
const component = new Component(fixtures.locator, fixtures.invocations)
|
|
11
13
|
|
|
12
14
|
beforeEach(() => {
|
|
13
|
-
|
|
15
|
+
resetCalls()
|
|
14
16
|
})
|
|
15
17
|
|
|
16
18
|
it('should invoke', async () => {
|
|
17
19
|
await component.invoke(name)
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
assert.ok(invocation.invoke.mock.callCount() > 0)
|
|
20
22
|
})
|
|
21
23
|
|
|
22
24
|
it('should throw on unknown invocation name', async () => {
|
|
23
|
-
await
|
|
24
|
-
.rejects.toMatchObject({ code: codes.NotImplemented })
|
|
25
|
+
await assert.rejects(() => component.invoke('baz'), AssertionError)
|
|
25
26
|
})
|
|
26
27
|
|
|
27
28
|
it('should invoke input and query', async () => {
|
|
@@ -29,12 +30,28 @@ describe('Invocations', () => {
|
|
|
29
30
|
const query = { test: Math.random() }
|
|
30
31
|
await component.invoke(name, { input, query })
|
|
31
32
|
|
|
32
|
-
|
|
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
|
+
)
|
|
33
40
|
})
|
|
34
41
|
|
|
35
42
|
it('should return io', async () => {
|
|
36
43
|
const io = await component.invoke(name)
|
|
37
44
|
|
|
38
|
-
|
|
45
|
+
assert.strictEqual(io, fixtures.invocations[name].invoke.mock.calls[0].result)
|
|
39
46
|
})
|
|
40
47
|
})
|
|
48
|
+
|
|
49
|
+
function resetCalls(target = [assert, fixtures], seen = new Set()) {
|
|
50
|
+
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
51
|
+
|
|
52
|
+
seen.add(target)
|
|
53
|
+
|
|
54
|
+
for (const value of Object.values(target))
|
|
55
|
+
if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
|
|
56
|
+
else resetCalls(value, seen)
|
|
57
|
+
}
|
|
@@ -1,40 +1,56 @@
|
|
|
1
|
-
|
|
1
|
+
import { random, timeout } from '@toa.io/generic'
|
|
2
|
+
import { Connector } from '../source/connector.js'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
const { Connector } = require('../src/connector')
|
|
5
|
-
|
|
6
|
-
class TestConnector extends Connector {
|
|
4
|
+
export class TestConnector extends Connector {
|
|
7
5
|
#label
|
|
8
6
|
#seq
|
|
9
7
|
|
|
10
|
-
constructor
|
|
8
|
+
constructor(label, seq) {
|
|
11
9
|
super()
|
|
12
10
|
|
|
13
11
|
this.#seq = seq
|
|
14
12
|
this.#label = label
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
async open
|
|
15
|
+
async open() {
|
|
18
16
|
await timeout(random(10))
|
|
19
17
|
this.#seq.push(`+${this.#label}`)
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
async close
|
|
20
|
+
async close() {
|
|
23
21
|
await timeout(random(10))
|
|
24
22
|
this.#seq.push(`-${this.#label}`)
|
|
25
23
|
}
|
|
26
24
|
|
|
27
|
-
async dispose
|
|
25
|
+
async dispose() {
|
|
28
26
|
this.#seq.push(`*${this.#label}`)
|
|
29
27
|
}
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
class FailingConnector extends Connector {
|
|
33
|
-
async open
|
|
30
|
+
export class FailingConnector extends Connector {
|
|
31
|
+
async open() {
|
|
34
32
|
await timeout(random(10))
|
|
35
33
|
throw new Error('FailingConnector')
|
|
36
34
|
}
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
/** Stands for a connector whose connection lands once it has been disconnected. */
|
|
38
|
+
export class LateConnector extends Connector {
|
|
39
|
+
#arrive
|
|
40
|
+
|
|
41
|
+
async open() {
|
|
42
|
+
await new Promise((resolve) => (this.#arrive = resolve))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Lets the connection land. */
|
|
46
|
+
arrive() {
|
|
47
|
+
this.#arrive()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Stands for a connector waiting for something that never arrives. */
|
|
52
|
+
export class StuckConnector extends Connector {
|
|
53
|
+
async open() {
|
|
54
|
+
return new Promise(() => undefined)
|
|
55
|
+
}
|
|
56
|
+
}
|