@toa.io/core 1.0.0-alpha.31 → 1.0.0-alpha.311
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/package.json +28 -12
- package/transpiled/abandon.d.ts +9 -0
- package/transpiled/abandon.js +37 -0
- package/transpiled/abandon.js.map +1 -0
- package/transpiled/assignment.d.ts +6 -0
- package/transpiled/assignment.js +25 -0
- package/transpiled/assignment.js.map +1 -0
- package/transpiled/call.d.ts +10 -0
- package/transpiled/call.js +165 -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 +148 -0
- package/transpiled/component.js.map +1 -0
- package/transpiled/composition.d.ts +6 -0
- package/transpiled/composition.js +20 -0
- package/transpiled/composition.js.map +1 -0
- package/transpiled/connector.d.ts +71 -0
- package/transpiled/connector.js +248 -0
- package/transpiled/connector.js.map +1 -0
- package/transpiled/context.d.ts +25 -0
- package/transpiled/context.js +55 -0
- package/transpiled/context.js.map +1 -0
- package/transpiled/contract/component.d.ts +24 -0
- package/transpiled/contract/component.js +48 -0
- package/transpiled/contract/component.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 +3 -0
- package/transpiled/contract/index.js +4 -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 +39 -0
- package/transpiled/contract/request.js +115 -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/deliveries.d.ts +22 -0
- package/transpiled/deliveries.js +31 -0
- package/transpiled/deliveries.js.map +1 -0
- package/transpiled/effect.d.ts +7 -0
- package/transpiled/effect.js +13 -0
- package/transpiled/effect.js.map +1 -0
- package/transpiled/emission.d.ts +10 -0
- package/transpiled/emission.js +16 -0
- package/transpiled/emission.js.map +1 -0
- package/transpiled/encoded.d.ts +16 -0
- package/transpiled/encoded.js +25 -0
- package/transpiled/encoded.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 +137 -0
- package/transpiled/entities/entity.js.map +1 -0
- package/transpiled/entities/factory.d.ts +27 -0
- package/transpiled/entities/factory.js +38 -0
- package/transpiled/entities/factory.js.map +1 -0
- package/transpiled/entities/index.d.ts +5 -0
- package/transpiled/entities/index.js +6 -0
- package/transpiled/entities/index.js.map +1 -0
- package/transpiled/entities/newid.d.ts +11 -0
- package/transpiled/entities/newid.js +41 -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 +53 -0
- package/transpiled/event.js.map +1 -0
- package/transpiled/exceptions.d.ts +104 -0
- package/transpiled/exceptions.js +205 -0
- package/transpiled/exceptions.js.map +1 -0
- package/transpiled/gate.d.ts +40 -0
- package/transpiled/gate.js +84 -0
- package/transpiled/gate.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/halting.d.ts +16 -0
- package/transpiled/halting.js +25 -0
- package/transpiled/halting.js.map +1 -0
- package/transpiled/index.d.ts +41 -0
- package/transpiled/index.js +34 -0
- package/transpiled/index.js.map +1 -0
- package/transpiled/instance.d.ts +10 -0
- package/transpiled/instance.js +30 -0
- package/transpiled/instance.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/measurements.d.ts +20 -0
- package/transpiled/measurements.js +40 -0
- package/transpiled/measurements.js.map +1 -0
- package/transpiled/observation.d.ts +7 -0
- package/transpiled/observation.js +14 -0
- package/transpiled/observation.js.map +1 -0
- package/transpiled/operation.d.ts +69 -0
- package/transpiled/operation.js +174 -0
- package/transpiled/operation.js.map +1 -0
- package/transpiled/outbox.d.ts +45 -0
- package/transpiled/outbox.js +448 -0
- package/transpiled/outbox.js.map +1 -0
- package/transpiled/outbox.measurements.d.ts +4 -0
- package/transpiled/outbox.measurements.js +38 -0
- package/transpiled/outbox.measurements.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 +34 -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 +113 -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 +11 -0
- package/transpiled/remote.js.map +1 -0
- package/transpiled/safety.d.ts +5 -0
- package/transpiled/safety.js +26 -0
- package/transpiled/safety.js.map +1 -0
- package/transpiled/state.d.ts +36 -0
- package/transpiled/state.js +131 -0
- package/transpiled/state.js.map +1 -0
- package/transpiled/trail.d.ts +78 -0
- package/transpiled/trail.js +112 -0
- package/transpiled/trail.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 +58 -0
- package/transpiled/types/atomicity.js +2 -0
- package/transpiled/types/atomicity.js.map +1 -0
- package/transpiled/types/bindings.d.ts +77 -0
- package/transpiled/types/bindings.js +2 -0
- package/transpiled/types/bindings.js.map +1 -0
- package/transpiled/types/bridges.d.ts +41 -0
- package/transpiled/types/bridges.js +2 -0
- package/transpiled/types/bridges.js.map +1 -0
- package/transpiled/types/extensions.d.ts +116 -0
- package/transpiled/types/extensions.js +2 -0
- package/transpiled/types/extensions.js.map +1 -0
- package/transpiled/types/inbox.d.ts +22 -0
- package/transpiled/types/inbox.js +2 -0
- package/transpiled/types/inbox.js.map +1 -0
- package/transpiled/types/index.d.ts +14 -0
- package/transpiled/types/index.js +9 -0
- package/transpiled/types/index.js.map +1 -0
- package/transpiled/types/message.d.ts +16 -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 +54 -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 +119 -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 +146 -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/src/assignment.js +0 -31
- package/src/call.js +0 -42
- package/src/cascade.js +0 -35
- 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 -38
- package/src/entities/entity.js +0 -74
- 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 -61
- package/src/reflection.js +0 -28
- package/src/remote.js +0 -17
- package/src/state.js +0 -99
- package/src/transition.js +0 -67
- package/src/transmission.js +0 -33
- package/test/call.fixtures.js +0 -27
- package/test/call.test.js +0 -46
- package/test/component.fixtures.js +0 -21
- package/test/component.test.js +0 -40
- package/test/connector.fixtures.js +0 -40
- package/test/connector.test.js +0 -176
- package/test/context.fixtures.js +0 -18
- package/test/context.test.js +0 -29
- package/test/contract/conditions.test.js +0 -26
- package/test/contract/contract.fixtures.js +0 -33
- package/test/contract/request.test.js +0 -112
- package/test/emission.fixtures.js +0 -17
- package/test/emission.test.js +0 -35
- package/test/entities/entity.fixtures.js +0 -29
- package/test/entities/entity.test.js +0 -65
- package/test/entities/factory.fixtures.js +0 -18
- package/test/entities/factory.test.js +0 -48
- package/test/entities/set.fixtures.js +0 -11
- package/test/entities/set.test.js +0 -12
- package/test/event.fixtures.js +0 -29
- package/test/event.test.js +0 -118
- package/test/locator.test.js +0 -113
- package/test/query.fixtures.js +0 -100
- package/test/query.test.js +0 -86
- package/test/receiver.fixtures.js +0 -23
- package/test/receiver.test.js +0 -95
- package/test/reflection.test.js +0 -30
- package/test/state.fixtures.js +0 -47
- package/test/state.test.js +0 -46
- package/test/transmission.fixtures.js +0 -15
- package/test/transmission.test.js +0 -46
- 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/message.d.ts +0 -3
- 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,71 @@
|
|
|
1
|
+
/** Abstract connections hierarchy */
|
|
2
|
+
export declare class Connector {
|
|
3
|
+
#private;
|
|
4
|
+
readonly id: string;
|
|
5
|
+
connected: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Whether this has been taken down. What is disposed of is never connected again: a
|
|
8
|
+
* communication it held is sealed, an announcement it made has stopped, an algorithm it ran
|
|
9
|
+
* is unmounted. Whoever remembers one for the life of the process — an extension factory
|
|
10
|
+
* caching what it hands to components — replaces it rather than handing it out twice.
|
|
11
|
+
*/
|
|
12
|
+
disposed: boolean;
|
|
13
|
+
constructor();
|
|
14
|
+
/**
|
|
15
|
+
* Creates a dependency and backlink with another Connector or a set of Connectors
|
|
16
|
+
*
|
|
17
|
+
* See .connect() and .disconnect()
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
depends(connector: Connector | Connector[]): Connector;
|
|
21
|
+
/**
|
|
22
|
+
* Creates a backlink to another Connector
|
|
23
|
+
*
|
|
24
|
+
* See .connect() and .disconnect()
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
27
|
+
link(connector: Connector): void;
|
|
28
|
+
/**
|
|
29
|
+
* Connects dependants then self
|
|
30
|
+
*
|
|
31
|
+
* In case of exception disconnects with current connection interruption
|
|
32
|
+
*
|
|
33
|
+
* Method is idempotent
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
connect(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Disconnects self then dependants
|
|
39
|
+
*
|
|
40
|
+
* Does nothing if there are connected linked Connectors
|
|
41
|
+
*
|
|
42
|
+
* Method is idempotent
|
|
43
|
+
*
|
|
44
|
+
*/
|
|
45
|
+
disconnect(interrupt?: boolean): Promise<void>;
|
|
46
|
+
reconnect(): Promise<void>;
|
|
47
|
+
debug(node?: Record<string, any>): Record<string, any>;
|
|
48
|
+
/** Called on connection */
|
|
49
|
+
/**
|
|
50
|
+
* Stops what this tree does of its own accord, holding every connection open.
|
|
51
|
+
*
|
|
52
|
+
* The walk is what reaches a connector; what the connector does about it is `stop`. Top down,
|
|
53
|
+
* so a source is stopped before whatever it feeds, and a failure is reported rather than
|
|
54
|
+
* raised — one connector that will not stop is no reason to leave the rest working.
|
|
55
|
+
*/
|
|
56
|
+
halt(visited?: Set<Connector>): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Starts again what `halt` stopped, bottom up, so nothing works before what it works through.
|
|
59
|
+
* Runs wherever the halt went, including where it failed.
|
|
60
|
+
*/
|
|
61
|
+
restore(visited?: Set<Connector>): Promise<void>;
|
|
62
|
+
/** What this stops doing of its own accord while the tree is halted. See `halt`. */
|
|
63
|
+
protected pause(): Promise<void> | void;
|
|
64
|
+
/** What it starts doing again. See `restore`. */
|
|
65
|
+
protected unpause(): Promise<void> | void;
|
|
66
|
+
protected open(): Promise<void> | void;
|
|
67
|
+
/** Called on disconnection */
|
|
68
|
+
protected close(): Promise<void> | void;
|
|
69
|
+
/** Called after self and dependants disconnection is complete */
|
|
70
|
+
protected dispose(): Promise<void> | void;
|
|
71
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { console } from 'openspan';
|
|
2
|
+
import { environment } from '@toa.io/generic';
|
|
3
|
+
/** Abstract connections hierarchy */
|
|
4
|
+
export class Connector {
|
|
5
|
+
#dependencies = [];
|
|
6
|
+
#links = [];
|
|
7
|
+
#connecting;
|
|
8
|
+
#disconnecting;
|
|
9
|
+
#discarded = false;
|
|
10
|
+
/** Whether this has been told to stop what it does of its own accord, see `halt`. */
|
|
11
|
+
#halted = false;
|
|
12
|
+
id;
|
|
13
|
+
connected = false;
|
|
14
|
+
/**
|
|
15
|
+
* Whether this has been taken down. What is disposed of is never connected again: a
|
|
16
|
+
* communication it held is sealed, an announcement it made has stopped, an algorithm it ran
|
|
17
|
+
* is unmounted. Whoever remembers one for the life of the process — an extension factory
|
|
18
|
+
* caching what it hands to components — replaces it rather than handing it out twice.
|
|
19
|
+
*/
|
|
20
|
+
disposed = false;
|
|
21
|
+
constructor() {
|
|
22
|
+
this.id = this.constructor.name + '#' + Math.random().toString(36).substring(2, 8);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Creates a dependency and backlink with another Connector or a set of Connectors
|
|
26
|
+
*
|
|
27
|
+
* See .connect() and .disconnect()
|
|
28
|
+
*
|
|
29
|
+
*/
|
|
30
|
+
depends(connector) {
|
|
31
|
+
let next;
|
|
32
|
+
if (connector instanceof Array) {
|
|
33
|
+
if (connector.length === 0)
|
|
34
|
+
throw new Error('Connectors array must not be empty');
|
|
35
|
+
if (connector.length > 1) {
|
|
36
|
+
next = new Connector();
|
|
37
|
+
for (const item of connector) {
|
|
38
|
+
this.#dependencies.push(item);
|
|
39
|
+
item.depends(next);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else
|
|
43
|
+
next = connector[0];
|
|
44
|
+
}
|
|
45
|
+
else
|
|
46
|
+
next = connector;
|
|
47
|
+
this.#dependencies.push(next);
|
|
48
|
+
next.link(this);
|
|
49
|
+
// See .#discard()
|
|
50
|
+
if (this.#disconnecting !== undefined)
|
|
51
|
+
next.#discard();
|
|
52
|
+
// and the same for a quiescence the walk has gone past already: one taken on after it
|
|
53
|
+
// would otherwise be the one thing in the tree still working
|
|
54
|
+
if (this.#halted)
|
|
55
|
+
void next.halt();
|
|
56
|
+
return next;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Disconnects, now and again if a connection is still to land.
|
|
60
|
+
*
|
|
61
|
+
* A dependency taken on after its dependant was disconnected — a lookup that returns
|
|
62
|
+
* once the teardown walk has gone by — is one nothing is left to take down, as the
|
|
63
|
+
* walk that would have reached it is over. One that stays connected holds open
|
|
64
|
+
* everything it depends on with it: a dependency reads `connected` of every dependant
|
|
65
|
+
* before it closes, and a dependant that is connected for good is a dependency that
|
|
66
|
+
* never closes.
|
|
67
|
+
*/
|
|
68
|
+
#discard() {
|
|
69
|
+
this.#discarded = true;
|
|
70
|
+
// one that is up already, or on its way, is taken down here; one that is not is
|
|
71
|
+
// taken down by the connection when it comes, and until then there is nothing to do
|
|
72
|
+
if (this.#connecting !== undefined)
|
|
73
|
+
void this.#drop();
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Creates a backlink to another Connector
|
|
77
|
+
*
|
|
78
|
+
* See .connect() and .disconnect()
|
|
79
|
+
*
|
|
80
|
+
*/
|
|
81
|
+
link(connector) {
|
|
82
|
+
this.#links.push(connector);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Connects dependants then self
|
|
86
|
+
*
|
|
87
|
+
* In case of exception disconnects with current connection interruption
|
|
88
|
+
*
|
|
89
|
+
* Method is idempotent
|
|
90
|
+
*
|
|
91
|
+
*/
|
|
92
|
+
async connect() {
|
|
93
|
+
if (this.#connecting)
|
|
94
|
+
return this.#connecting;
|
|
95
|
+
this.#disconnecting = undefined;
|
|
96
|
+
const work = async () => {
|
|
97
|
+
await Promise.all(this.#dependencies.map((connector) => connector.connect()));
|
|
98
|
+
await this.open();
|
|
99
|
+
};
|
|
100
|
+
// anonymous grouping nodes are not worth a span
|
|
101
|
+
const connecting = TRACE_BOOT && this.constructor.name !== 'Connector'
|
|
102
|
+
? console.span({
|
|
103
|
+
name: `connect ${this.constructor.name}`,
|
|
104
|
+
// a connector that has a locator is named by it; a grouping node has none
|
|
105
|
+
attributes: { id: this.locator?.id ?? this.id }
|
|
106
|
+
}, work)
|
|
107
|
+
: work();
|
|
108
|
+
this.#connecting = connecting;
|
|
109
|
+
try {
|
|
110
|
+
await connecting;
|
|
111
|
+
/*
|
|
112
|
+
* A disconnection that did not wait for this connection emptied `#connecting` to
|
|
113
|
+
* say so. Reporting `connected` now would report it of a connector nothing takes
|
|
114
|
+
* down again — its `#disconnecting` has settled, so a later call returns at once —
|
|
115
|
+
* and what it depends on reads that of every dependant before it closes.
|
|
116
|
+
*/
|
|
117
|
+
if (this.#connecting === connecting)
|
|
118
|
+
this.connected = true;
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
await this.disconnect(true);
|
|
122
|
+
throw e;
|
|
123
|
+
}
|
|
124
|
+
// a connection asked for before this one was discarded, landing after. See .#discard()
|
|
125
|
+
if (this.#discarded)
|
|
126
|
+
await this.#drop();
|
|
127
|
+
}
|
|
128
|
+
/** Disconnects a discarded connector, saying so rather than throwing at whoever is not waiting. */
|
|
129
|
+
async #drop() {
|
|
130
|
+
this.#discarded = false;
|
|
131
|
+
try {
|
|
132
|
+
await this.disconnect();
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
console.error('Discarded connector failed to disconnect', { id: this.id, error });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Disconnects self then dependants
|
|
140
|
+
*
|
|
141
|
+
* Does nothing if there are connected linked Connectors
|
|
142
|
+
*
|
|
143
|
+
* Method is idempotent
|
|
144
|
+
*
|
|
145
|
+
*/
|
|
146
|
+
async disconnect(interrupt) {
|
|
147
|
+
// a connector that has not finished connecting has nothing to close, and
|
|
148
|
+
// awaiting a connection that may never settle outlives any grace period
|
|
149
|
+
const pending = interrupt === true || this.connected === false;
|
|
150
|
+
if (!pending)
|
|
151
|
+
await this.#connecting;
|
|
152
|
+
if (this.#disconnecting)
|
|
153
|
+
return this.#disconnecting;
|
|
154
|
+
const linked = this.#links.reduce((acc, parent) => acc || parent.connected, false);
|
|
155
|
+
if (linked && interrupt !== true)
|
|
156
|
+
return;
|
|
157
|
+
this.#disconnecting = (async () => {
|
|
158
|
+
const start = +new Date();
|
|
159
|
+
const interval = setInterval(() => {
|
|
160
|
+
const delay = +new Date() - start;
|
|
161
|
+
if (delay > DELAY)
|
|
162
|
+
console.warn(`Connector ${this.id} still disconnecting (${delay})`);
|
|
163
|
+
}, DELAY);
|
|
164
|
+
if (!pending)
|
|
165
|
+
await this.close();
|
|
166
|
+
// said once the closing is done rather than when it starts: a dependant that is
|
|
167
|
+
// still closing is still using what it depends on, and the check above reads this
|
|
168
|
+
// of every dependant. Saying it early lets the first to start tear down a shared
|
|
169
|
+
// dependency under the others.
|
|
170
|
+
this.connected = false;
|
|
171
|
+
this.#connecting = undefined;
|
|
172
|
+
clearInterval(interval);
|
|
173
|
+
await Promise.all(this.#dependencies.map((connector) => connector.disconnect()));
|
|
174
|
+
await this.dispose();
|
|
175
|
+
this.disposed = true;
|
|
176
|
+
})();
|
|
177
|
+
await this.#disconnecting;
|
|
178
|
+
}
|
|
179
|
+
async reconnect() {
|
|
180
|
+
await this.disconnect();
|
|
181
|
+
await this.connect();
|
|
182
|
+
}
|
|
183
|
+
debug(node = {}) {
|
|
184
|
+
node[this.id] = { connected: this.connected };
|
|
185
|
+
if (this.#dependencies.length > 0)
|
|
186
|
+
for (const connector of this.#dependencies)
|
|
187
|
+
connector.debug?.(node[this.id]);
|
|
188
|
+
return node;
|
|
189
|
+
}
|
|
190
|
+
/** Called on connection */
|
|
191
|
+
/**
|
|
192
|
+
* Stops what this tree does of its own accord, holding every connection open.
|
|
193
|
+
*
|
|
194
|
+
* The walk is what reaches a connector; what the connector does about it is `stop`. Top down,
|
|
195
|
+
* so a source is stopped before whatever it feeds, and a failure is reported rather than
|
|
196
|
+
* raised — one connector that will not stop is no reason to leave the rest working.
|
|
197
|
+
*/
|
|
198
|
+
async halt(visited = new Set()) {
|
|
199
|
+
// the walk is governed by where it has been, and the flag only by whether this one has
|
|
200
|
+
// already stopped: a connector that has, with a subtree that has not, is still walked through
|
|
201
|
+
if (visited.has(this))
|
|
202
|
+
return;
|
|
203
|
+
visited.add(this);
|
|
204
|
+
if (!this.#halted) {
|
|
205
|
+
this.#halted = true;
|
|
206
|
+
try {
|
|
207
|
+
await this.pause();
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
console.error('Connector failed to pause', { id: this.id, error });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
for (const dependency of this.#dependencies)
|
|
214
|
+
await dependency.halt(visited);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Starts again what `halt` stopped, bottom up, so nothing works before what it works through.
|
|
218
|
+
* Runs wherever the halt went, including where it failed.
|
|
219
|
+
*/
|
|
220
|
+
async restore(visited = new Set()) {
|
|
221
|
+
if (visited.has(this))
|
|
222
|
+
return;
|
|
223
|
+
visited.add(this);
|
|
224
|
+
for (const dependency of this.#dependencies)
|
|
225
|
+
await dependency.restore(visited);
|
|
226
|
+
if (!this.#halted)
|
|
227
|
+
return;
|
|
228
|
+
this.#halted = false;
|
|
229
|
+
try {
|
|
230
|
+
await this.unpause();
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
console.error('Connector failed to unpause', { id: this.id, error });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/** What this stops doing of its own accord while the tree is halted. See `halt`. */
|
|
237
|
+
pause() { }
|
|
238
|
+
/** What it starts doing again. See `restore`. */
|
|
239
|
+
unpause() { }
|
|
240
|
+
open() { }
|
|
241
|
+
/** Called on disconnection */
|
|
242
|
+
close() { }
|
|
243
|
+
/** Called after self and dependants disconnection is complete */
|
|
244
|
+
dispose() { }
|
|
245
|
+
}
|
|
246
|
+
const DELAY = 5000;
|
|
247
|
+
const TRACE_BOOT = environment.get('TOA_BOOT_TRACE') === '1';
|
|
248
|
+
//# sourceMappingURL=connector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector.js","sourceRoot":"","sources":["../source/connector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Connector } from './connector.ts';
|
|
2
|
+
import type { Locator } from './locator.ts';
|
|
3
|
+
import type { Component } from './component.ts';
|
|
4
|
+
import type { Remote } from './remote.ts';
|
|
5
|
+
import type { Aspect } from './types/extensions.ts';
|
|
6
|
+
import type { Options, Request } from './types/request.ts';
|
|
7
|
+
type Discover = (namespace: string, name: string) => Promise<Remote>;
|
|
8
|
+
export declare class Context extends Connector {
|
|
9
|
+
#private;
|
|
10
|
+
readonly env: string | undefined;
|
|
11
|
+
readonly name: string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* The rank of the region this deployment is, which is what its writes are stamped with. A
|
|
14
|
+
* deployment that is no region at all reads as zero, which is what its records carry.
|
|
15
|
+
*/
|
|
16
|
+
readonly region: number;
|
|
17
|
+
readonly aspects: Aspect[];
|
|
18
|
+
readonly locator: Locator;
|
|
19
|
+
/** The name this process answers addressed calls under. */
|
|
20
|
+
readonly instance: string;
|
|
21
|
+
constructor(local: Component, discover: Discover, aspects?: Aspect[]);
|
|
22
|
+
apply(endpoint: string, request: Request, options?: Options): Promise<any>;
|
|
23
|
+
call(namespace: string, name: string, endpoint: string, request: Request, options?: Options): Promise<any>;
|
|
24
|
+
}
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Connector } from './connector.js';
|
|
2
|
+
import { waiting } from './abandon.js';
|
|
3
|
+
import { instance } from './instance.js';
|
|
4
|
+
import { environment } from '@toa.io/generic';
|
|
5
|
+
export class Context extends Connector {
|
|
6
|
+
env;
|
|
7
|
+
name;
|
|
8
|
+
/**
|
|
9
|
+
* The rank of the region this deployment is, which is what its writes are stamped with. A
|
|
10
|
+
* deployment that is no region at all reads as zero, which is what its records carry.
|
|
11
|
+
*/
|
|
12
|
+
region;
|
|
13
|
+
aspects;
|
|
14
|
+
locator;
|
|
15
|
+
/** The name this process answers addressed calls under. */
|
|
16
|
+
instance;
|
|
17
|
+
#local;
|
|
18
|
+
#discover;
|
|
19
|
+
#remotes = {};
|
|
20
|
+
constructor(local, discover, aspects = []) {
|
|
21
|
+
super();
|
|
22
|
+
this.env = environment.get('TOA_ENV');
|
|
23
|
+
this.name = environment.get('TOA_CONTEXT');
|
|
24
|
+
this.region = Number(environment.get('TOA_REGION') ?? 0);
|
|
25
|
+
this.aspects = aspects;
|
|
26
|
+
this.locator = local?.locator;
|
|
27
|
+
this.instance = instance();
|
|
28
|
+
this.#local = local;
|
|
29
|
+
this.#discover = discover;
|
|
30
|
+
this.depends(local);
|
|
31
|
+
if (aspects.length > 0)
|
|
32
|
+
this.depends(aspects);
|
|
33
|
+
}
|
|
34
|
+
async apply(endpoint, request, options) {
|
|
35
|
+
return this.#local.invoke(endpoint, request, options);
|
|
36
|
+
}
|
|
37
|
+
// eslint-disable-next-line max-params
|
|
38
|
+
async call(namespace, name, endpoint, request, options) {
|
|
39
|
+
// the lookup is waited for as the call is: a caller that stops waiting is answered at once, and
|
|
40
|
+
// the lookup finishes for the next call to use
|
|
41
|
+
const remote = await waiting(this.#remote(namespace, name), options?.signal, `${namespace}.${name}.${endpoint}`);
|
|
42
|
+
return remote.invoke(endpoint, request, options);
|
|
43
|
+
}
|
|
44
|
+
async #remote(namespace, name) {
|
|
45
|
+
const key = namespace + '.' + name;
|
|
46
|
+
this.#remotes[key] ??= this.#connect(namespace, name);
|
|
47
|
+
return this.#remotes[key];
|
|
48
|
+
}
|
|
49
|
+
async #connect(namespace, name) {
|
|
50
|
+
const remote = await this.#discover(namespace, name);
|
|
51
|
+
this.depends(remote);
|
|
52
|
+
return remote;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../source/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAS7C,MAAM,OAAO,OAAQ,SAAQ,SAAS;IACpB,GAAG,CAAoB;IACvB,IAAI,CAAoB;IAExC;;;OAGG;IACa,MAAM,CAAQ;IAEd,OAAO,CAAU;IACjB,OAAO,CAAS;IAEhC,2DAA2D;IAC3C,QAAQ,CAAQ;IAEvB,MAAM,CAAW;IACjB,SAAS,CAAU;IACnB,QAAQ,GAAoC,EAAE,CAAA;IAEvD,YAAmB,KAAgB,EAAE,QAAkB,EAAE,OAAO,GAAa,EAAE;QAC7E,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACrC,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;QAC1C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;QACxD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,EAAE,OAAO,CAAA;QAC7B,IAAI,CAAC,QAAQ,GAAG,QAAQ,EAAE,CAAA;QAE1B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;QACnB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAA;QAEzB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAEnB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/C,CAAC;IAEM,KAAK,CAAC,KAAK,CAAC,QAAgB,EAAE,OAAgB,EAAE,OAAiB;QACtE,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IACvD,CAAC;IAED,sCAAsC;IAC/B,KAAK,CAAC,IAAI,CACf,SAAiB,EACjB,IAAY,EACZ,QAAgB,EAChB,OAAgB,EAChB,OAAiB;QAEjB,gGAAgG;QAChG,+CAA+C;QAC/C,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,EAC7B,OAAO,EAAE,MAAM,EACf,GAAG,SAAS,IAAI,IAAI,IAAI,QAAQ,EAAE,CACnC,CAAA;QAED,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IAClD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,IAAY;QAC3C,MAAM,GAAG,GAAG,SAAS,GAAG,GAAG,GAAG,IAAI,CAAA;QAElC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QAErD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,SAAiB,EAAE,IAAY;QAC5C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QAEpD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAEpB,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Definition, Entity } from './request.ts';
|
|
2
|
+
/** What a caller is given in order to call a component: what a map states of it. */
|
|
3
|
+
export interface Contract {
|
|
4
|
+
/** the version of the component this describes */
|
|
5
|
+
version?: string;
|
|
6
|
+
entity?: Entity;
|
|
7
|
+
operations?: Record<string, Operation>;
|
|
8
|
+
events?: Record<string, Event>;
|
|
9
|
+
}
|
|
10
|
+
export interface Operation extends Definition {
|
|
11
|
+
bindings?: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface Event {
|
|
14
|
+
binding: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* What a caller is given of a component, of what its normalised manifest holds.
|
|
18
|
+
*
|
|
19
|
+
* What a component states about serving a call rather than about making one is its own: an
|
|
20
|
+
* operation's concurrency, the bridge that runs it and what it forwards to, and the entity's
|
|
21
|
+
* storage, its blank and its migrations. An event's `path` is a path in the process that
|
|
22
|
+
* normalised the manifest, and names nothing in any other.
|
|
23
|
+
*/
|
|
24
|
+
export declare function component(manifest: Contract): Contract;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a caller is given of a component, of what its normalised manifest holds.
|
|
3
|
+
*
|
|
4
|
+
* What a component states about serving a call rather than about making one is its own: an
|
|
5
|
+
* operation's concurrency, the bridge that runs it and what it forwards to, and the entity's
|
|
6
|
+
* storage, its blank and its migrations. An event's `path` is a path in the process that
|
|
7
|
+
* normalised the manifest, and names nothing in any other.
|
|
8
|
+
*/
|
|
9
|
+
export function component(manifest) {
|
|
10
|
+
const contract = { version: manifest.version };
|
|
11
|
+
if (manifest.entity !== undefined)
|
|
12
|
+
contract.entity = {
|
|
13
|
+
properties: manifest.entity.properties,
|
|
14
|
+
required: manifest.entity.required
|
|
15
|
+
};
|
|
16
|
+
if (manifest.operations !== undefined) {
|
|
17
|
+
contract.operations = {};
|
|
18
|
+
for (const [endpoint, definition] of Object.entries(manifest.operations))
|
|
19
|
+
contract.operations[endpoint] = operation(definition);
|
|
20
|
+
}
|
|
21
|
+
if (manifest.events !== undefined) {
|
|
22
|
+
contract.events = {};
|
|
23
|
+
for (const [event, definition] of Object.entries(manifest.events))
|
|
24
|
+
contract.events[event] = { binding: definition.binding };
|
|
25
|
+
}
|
|
26
|
+
return contract;
|
|
27
|
+
}
|
|
28
|
+
function operation(definition) {
|
|
29
|
+
const operation = {};
|
|
30
|
+
for (const key of KEYS)
|
|
31
|
+
if (definition[key] !== undefined)
|
|
32
|
+
operation[key] = definition[key];
|
|
33
|
+
return operation;
|
|
34
|
+
}
|
|
35
|
+
/** What a call to an operation is addressed by, carries, answers and refuses with. */
|
|
36
|
+
const KEYS = [
|
|
37
|
+
'type',
|
|
38
|
+
'scope',
|
|
39
|
+
'query',
|
|
40
|
+
'once',
|
|
41
|
+
'stateful',
|
|
42
|
+
'bindings',
|
|
43
|
+
'description',
|
|
44
|
+
'input',
|
|
45
|
+
'output',
|
|
46
|
+
'errors'
|
|
47
|
+
];
|
|
48
|
+
//# sourceMappingURL=component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../source/contract/component.ts"],"names":[],"mappings":"AAmBA;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,QAAkB;IAC1C,MAAM,QAAQ,GAAa,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAA;IAExD,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS;QAC/B,QAAQ,CAAC,MAAM,GAAG;YAChB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU;YACtC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;SACnC,CAAA;IAEH,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACtC,QAAQ,CAAC,UAAU,GAAG,EAAE,CAAA;QAExB,KAAK,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;YACtE,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,CAAA;IACzD,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAClC,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAA;QAEpB,KAAK,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC/D,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,CAAA;IAC5D,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,SAAS,SAAS,CAAC,UAAqB;IACtC,MAAM,SAAS,GAA4B,EAAE,CAAA;IAE7C,KAAK,MAAM,GAAG,IAAI,IAAI;QACpB,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,SAAS,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAA;IAErE,OAAO,SAAsB,CAAA;AAC/B,CAAC;AAED,sFAAsF;AACtF,MAAM,IAAI,GAAG;IACX,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,UAAU;IACV,UAAU;IACV,aAAa;IACb,OAAO;IACP,QAAQ;IACR,QAAQ;CACiC,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Schema, SchemaError } from '@toa.io/schemas';
|
|
2
|
+
import type { Exception } from '../exceptions.ts';
|
|
3
|
+
/** What a contract throws with, stated by the subclass. */
|
|
4
|
+
export type Refusal = new (error: SchemaError, cause?: unknown) => Exception;
|
|
5
|
+
export declare class Contract {
|
|
6
|
+
readonly schema: Schema;
|
|
7
|
+
static Exception: Refusal;
|
|
8
|
+
constructor(schema: Schema);
|
|
9
|
+
fit(value: unknown): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SystemException } from '../exceptions.js';
|
|
2
|
+
export class Contract {
|
|
3
|
+
schema;
|
|
4
|
+
static Exception = SystemException;
|
|
5
|
+
constructor(schema) {
|
|
6
|
+
this.schema = schema;
|
|
7
|
+
}
|
|
8
|
+
fit(value) {
|
|
9
|
+
const error = this.schema.fit(value);
|
|
10
|
+
if (error !== null)
|
|
11
|
+
throw new this.constructor.Exception(error, value);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../source/contract/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAOlD,MAAM,OAAO,QAAQ;IACH,MAAM,CAAQ;IAEvB,MAAM,CAAC,SAAS,GAAY,eAAqC,CAAA;IAExE,YAAmB,MAAc;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAEM,GAAG,CAAC,KAAc;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAEpC,IAAI,KAAK,KAAK,IAAI;YAChB,MAAM,IAAK,IAAI,CAAC,WAA+B,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IAC3E,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/contract/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Contract } from './contract.ts';
|
|
2
|
+
import type { Refusal } from './contract.ts';
|
|
3
|
+
import type { JSONSchema } from './schemas.ts';
|
|
4
|
+
export declare class Reply extends Contract {
|
|
5
|
+
static Exception: Refusal;
|
|
6
|
+
static schema(output?: JSONSchema, errors?: Array<string | number>): JSONSchema;
|
|
7
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Contract } from './contract.js';
|
|
2
|
+
import { ResponseContractException } from '../exceptions.js';
|
|
3
|
+
export class Reply extends Contract {
|
|
4
|
+
static Exception = ResponseContractException;
|
|
5
|
+
static schema(output, errors) {
|
|
6
|
+
const schema = {
|
|
7
|
+
type: 'object',
|
|
8
|
+
properties: {},
|
|
9
|
+
additionalProperties: false
|
|
10
|
+
};
|
|
11
|
+
if (output !== undefined) {
|
|
12
|
+
/*
|
|
13
|
+
* A reply carries more than the operation declares — `VERSION` and the rest of the
|
|
14
|
+
* record's own fields — so what it is validated against is the declaration relaxed.
|
|
15
|
+
* On a copy: the declaration itself is what a component publishes when asked to
|
|
16
|
+
* explain, and relaxing that would publish a contract nobody wrote.
|
|
17
|
+
*/
|
|
18
|
+
output = structuredClone(output);
|
|
19
|
+
if (output.type === 'object')
|
|
20
|
+
output.additionalProperties = true;
|
|
21
|
+
else if (output.type === 'array' && output.items?.type === 'object')
|
|
22
|
+
output.items.additionalProperties = true;
|
|
23
|
+
schema.properties.output = output;
|
|
24
|
+
}
|
|
25
|
+
/*
|
|
26
|
+
* An error a caller is meant to handle is one the operation states. Where none are
|
|
27
|
+
* stated, an error is not a reply this operation makes — it is a mistake, and the
|
|
28
|
+
* contract says so rather than passing an undeclared code on to whoever called.
|
|
29
|
+
*/
|
|
30
|
+
schema.properties.error =
|
|
31
|
+
errors === undefined
|
|
32
|
+
? false
|
|
33
|
+
: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: {
|
|
36
|
+
code: {
|
|
37
|
+
enum: errors
|
|
38
|
+
},
|
|
39
|
+
message: {
|
|
40
|
+
type: 'string'
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
required: ['code']
|
|
44
|
+
};
|
|
45
|
+
return schema;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=reply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply.js","sourceRoot":"","sources":["../../source/contract/reply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAA;AAI5D,MAAM,OAAO,KAAM,SAAQ,QAAQ;IAC1B,MAAM,CAAU,SAAS,GAC9B,yBAA+C,CAAA;IAE1C,MAAM,CAAC,MAAM,CAAC,MAAmB,EAAE,MAA+B;QACvE,MAAM,MAAM,GAAe;YACzB,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE;YACd,oBAAoB,EAAE,KAAK;SAC5B,CAAA;QAED,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB;;;;;eAKG;YACH,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAA;YAEhC,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,CAAC,oBAAoB,GAAG,IAAI,CAAA;iBAC3D,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,IAAI,KAAK,QAAQ;gBACjE,MAAM,CAAC,KAAK,CAAC,oBAAoB,GAAG,IAAI,CAAA;YAE1C,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,MAAM,CAAA;QACnC,CAAC;QAED;;;;WAIG;QACH,MAAM,CAAC,UAAU,CAAC,KAAK;YACrB,MAAM,KAAK,SAAS;gBAClB,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC;oBACE,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,IAAI,EAAE;4BACJ,IAAI,EAAE,MAAM;yBACb;wBACD,OAAO,EAAE;4BACP,IAAI,EAAE,QAAQ;yBACf;qBACF;oBACD,QAAQ,EAAE,CAAC,MAAM,CAAC;iBACnB,CAAA;QAEP,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Contract } from './contract.ts';
|
|
2
|
+
import type { Schema } from '@toa.io/schemas';
|
|
3
|
+
import type { Refusal } from './contract.ts';
|
|
4
|
+
import type { JSONSchema } from './schemas.ts';
|
|
5
|
+
/** What an operation states about itself, and answers when asked to explain. */
|
|
6
|
+
export interface Explanation {
|
|
7
|
+
description?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Whether the same call arriving twice changes state once. Said, because a caller cannot tell
|
|
10
|
+
* it from an answer that says nothing, and what it changes is whether a retry is safe to make.
|
|
11
|
+
*/
|
|
12
|
+
once?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Whether a call to it names the process it goes to. Said, because the caller is the one who
|
|
15
|
+
* has to name one, and a call that names none is refused.
|
|
16
|
+
*/
|
|
17
|
+
stateful?: boolean;
|
|
18
|
+
input?: JSONSchema | null;
|
|
19
|
+
output?: JSONSchema | null;
|
|
20
|
+
errors?: Array<string | number>;
|
|
21
|
+
}
|
|
22
|
+
export interface Definition extends Explanation {
|
|
23
|
+
type?: string;
|
|
24
|
+
scope?: string;
|
|
25
|
+
query?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** What the operation works on, as the manifest declares it. */
|
|
28
|
+
export interface Entity {
|
|
29
|
+
properties: Record<string, JSONSchema>;
|
|
30
|
+
required?: string[];
|
|
31
|
+
}
|
|
32
|
+
export declare class Request extends Contract {
|
|
33
|
+
readonly discovery: Explanation;
|
|
34
|
+
static Exception: Refusal;
|
|
35
|
+
constructor(schema: Schema, definition: Definition, entity?: Entity);
|
|
36
|
+
static schema(definition: Definition, entity?: {
|
|
37
|
+
properties: Record<string, JSONSchema>;
|
|
38
|
+
}): JSONSchema;
|
|
39
|
+
}
|