@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
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/core",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.311",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "Toa Core",
|
|
5
6
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
7
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -11,23 +12,38 @@
|
|
|
11
12
|
"bugs": {
|
|
12
13
|
"url": "https://github.com/toa-io/toa/issues"
|
|
13
14
|
},
|
|
14
|
-
"main": "
|
|
15
|
-
"types": "
|
|
15
|
+
"main": "transpiled/index.js",
|
|
16
|
+
"types": "transpiled/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./transpiled/index.d.ts",
|
|
20
|
+
"default": "./transpiled/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./types": {
|
|
23
|
+
"types": "./transpiled/types/index.d.ts",
|
|
24
|
+
"default": "./transpiled/types/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
16
28
|
"publishConfig": {
|
|
17
29
|
"access": "public"
|
|
18
30
|
},
|
|
31
|
+
"files": [
|
|
32
|
+
"transpiled",
|
|
33
|
+
"!**/tsconfig.tsbuildinfo",
|
|
34
|
+
"!**/*.test.*",
|
|
35
|
+
"!**/.env*"
|
|
36
|
+
],
|
|
19
37
|
"scripts": {
|
|
38
|
+
"transpile": "tsc",
|
|
20
39
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
21
40
|
},
|
|
22
41
|
"dependencies": {
|
|
23
|
-
"@rsql/parser": "1.
|
|
24
|
-
"@toa.io/
|
|
25
|
-
"@toa.io/
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
},
|
|
29
|
-
"devDependencies": {
|
|
30
|
-
"clone-deep": "4.0.1"
|
|
42
|
+
"@rsql/parser": "1.6.0",
|
|
43
|
+
"@toa.io/generic": "1.0.0-alpha.311",
|
|
44
|
+
"@toa.io/schemas": "1.0.0-alpha.311",
|
|
45
|
+
"openspan": "1.0.0-alpha.305",
|
|
46
|
+
"uuid": "14.0.2"
|
|
31
47
|
},
|
|
32
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "4f45061964e275296a27ff8ff39f757ce27d4008"
|
|
33
49
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Exception } from './exceptions.ts';
|
|
2
|
+
/** What a caller that stopped waiting for `target` is told. */
|
|
3
|
+
export declare function abandoned(target: string, signal: AbortSignal): Exception;
|
|
4
|
+
/**
|
|
5
|
+
* What the promise settles with, or *abandoned* once the signal aborts, whichever comes first — at
|
|
6
|
+
* once where it has aborted already. The promise goes on running, and settles with nobody waiting
|
|
7
|
+
* for it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function waiting<T>(promise: Promise<T>, signal: AbortSignal | undefined, target: string): Promise<T>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AbandonedException } from './exceptions.js';
|
|
2
|
+
/** What a caller that stopped waiting for `target` is told. */
|
|
3
|
+
export function abandoned(target, signal) {
|
|
4
|
+
return new AbandonedException(`'${target}' went unanswered`, signal.reason);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* What the promise settles with, or *abandoned* once the signal aborts, whichever comes first — at
|
|
8
|
+
* once where it has aborted already. The promise goes on running, and settles with nobody waiting
|
|
9
|
+
* for it.
|
|
10
|
+
*/
|
|
11
|
+
export async function waiting(promise, signal, target) {
|
|
12
|
+
if (signal === undefined)
|
|
13
|
+
return await promise;
|
|
14
|
+
if (signal.aborted) {
|
|
15
|
+
promise.catch(noop);
|
|
16
|
+
throw abandoned(target, signal);
|
|
17
|
+
}
|
|
18
|
+
let abort = noop;
|
|
19
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
20
|
+
abort = () => reject(abandoned(target, signal));
|
|
21
|
+
});
|
|
22
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
23
|
+
try {
|
|
24
|
+
return await Promise.race([promise, aborted]);
|
|
25
|
+
}
|
|
26
|
+
catch (exception) {
|
|
27
|
+
// however the wait ended — here, or in whatever was carrying it
|
|
28
|
+
if (signal.aborted)
|
|
29
|
+
throw abandoned(target, signal);
|
|
30
|
+
throw exception;
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
signal.removeEventListener('abort', abort);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function noop() { }
|
|
37
|
+
//# sourceMappingURL=abandon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abandon.js","sourceRoot":"","sources":["../source/abandon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAGpD,+DAA+D;AAC/D,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,MAAmB;IAC3D,OAAO,IAAI,kBAAkB,CAAC,IAAI,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;AAC7E,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAAmB,EACnB,MAA+B,EAC/B,MAAc;IAEd,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,OAAO,CAAA;IAE9C,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAEnB,MAAM,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,CAAC;IAED,IAAI,KAAK,GAAe,IAAI,CAAA;IAE5B,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE;QACtD,KAAK,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAEvD,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAA;IAC/C,CAAC;IAAC,OAAO,SAAS,EAAE,CAAC;QACnB,gEAAgE;QAChE,IAAI,MAAM,CAAC,OAAO;YAAE,MAAM,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAEnD,MAAM,SAAS,CAAA;IACjB,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC5C,CAAC;AACH,CAAC;AAED,SAAS,IAAI,KAAU,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Operation } from './operation.js';
|
|
2
|
+
export class Assignment extends Operation {
|
|
3
|
+
async acquire(store) {
|
|
4
|
+
const changeset = this.scope.changeset(store.request.query);
|
|
5
|
+
store.scope = changeset;
|
|
6
|
+
store.state = changeset.get();
|
|
7
|
+
}
|
|
8
|
+
async commit(store) {
|
|
9
|
+
const { scope, state, reply, request } = store;
|
|
10
|
+
if (reply.error !== undefined)
|
|
11
|
+
return;
|
|
12
|
+
const changeset = scope;
|
|
13
|
+
changeset.set(state);
|
|
14
|
+
/*
|
|
15
|
+
* The call carries the reply as it stands, which is empty where the algorithm named no
|
|
16
|
+
* output — the storage fills it with the post-image it computes, because that is where the
|
|
17
|
+
* post-image is known.
|
|
18
|
+
*/
|
|
19
|
+
const output = await this.scope.apply(changeset, request.input, this.call(store));
|
|
20
|
+
// assignment returns new state by default
|
|
21
|
+
if (store.reply.output === undefined)
|
|
22
|
+
store.reply.output = output;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=assignment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assignment.js","sourceRoot":"","sources":["../source/assignment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAI1C,MAAM,OAAO,UAAW,SAAQ,SAAS;IACpB,KAAK,CAAC,OAAO,CAAC,KAAY;QAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,KAAY,CAAC,CAAA;QAElE,KAAK,CAAC,KAAK,GAAG,SAAS,CAAA;QACvB,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,EAAE,CAAA;IAC/B,CAAC;IAEkB,KAAK,CAAC,MAAM,CAAC,KAAY;QAC1C,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,KAAK,CAAA;QAE9C,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;YAAE,OAAM;QAErC,MAAM,SAAS,GAAG,KAAkB,CAAA;QAEpC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAEpB;;;;WAIG;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;QAEjF,0CAA0C;QAC1C,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAA;IACnE,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Connector } from './connector.ts';
|
|
2
|
+
import type { Transmission } from './transmission.ts';
|
|
3
|
+
import type { Request as Contract } from './contract/request.ts';
|
|
4
|
+
import type { Options, Request, Source } from './types/request.ts';
|
|
5
|
+
export declare class Call extends Connector {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(transmitter: Transmission, contract: Contract, target: string, source?: Source, stateful?: boolean, safe?: boolean);
|
|
8
|
+
invoke(request?: Request, options?: Options): Promise<any>;
|
|
9
|
+
explain(): any;
|
|
10
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
import { current, encode } from 'openspan';
|
|
3
|
+
import { Connector } from './connector.js';
|
|
4
|
+
import { derive, newid } from './entities/newid.js';
|
|
5
|
+
import { RequestContractException, SafetyException } from './exceptions.js';
|
|
6
|
+
import { abandoned, waiting } from './abandon.js';
|
|
7
|
+
import * as addressed from './instance.js';
|
|
8
|
+
import * as trail from './trail.js';
|
|
9
|
+
export class Call extends Connector {
|
|
10
|
+
#transmitter;
|
|
11
|
+
#contract;
|
|
12
|
+
/** what this calls, as a hop is named, so that an identity derived here names it too */
|
|
13
|
+
#target;
|
|
14
|
+
#source;
|
|
15
|
+
/** whether a call to it names the process it goes to */
|
|
16
|
+
#stateful;
|
|
17
|
+
/** whether what it calls is incapable of changing the State; see `safety.ts` */
|
|
18
|
+
#safe;
|
|
19
|
+
// eslint-disable-next-line max-params
|
|
20
|
+
constructor(transmitter, contract, target, source, stateful = false, safe = false) {
|
|
21
|
+
super();
|
|
22
|
+
this.#transmitter = transmitter;
|
|
23
|
+
this.#contract = contract;
|
|
24
|
+
this.#target = target;
|
|
25
|
+
this.#source = source;
|
|
26
|
+
this.#stateful = stateful;
|
|
27
|
+
this.#safe = safe;
|
|
28
|
+
this.depends(transmitter);
|
|
29
|
+
}
|
|
30
|
+
async invoke(request = {}, options = {}) {
|
|
31
|
+
const invocation = trail.current();
|
|
32
|
+
/*
|
|
33
|
+
* The process a call goes to, which the transmission is handed beside what the call asks, and
|
|
34
|
+
* what the caller said of reading, which is not the answer on its own.
|
|
35
|
+
*/
|
|
36
|
+
const { instance, readonly: stated, ...asked } = request;
|
|
37
|
+
/*
|
|
38
|
+
* The disjunction is what makes it a guarantee rather than a convention: a caller under a
|
|
39
|
+
* readonly invocation cannot clear it for a call of its own.
|
|
40
|
+
*/
|
|
41
|
+
const readonly = stated === true || invocation?.readonly === true;
|
|
42
|
+
this.#refuse(request, options, readonly);
|
|
43
|
+
/*
|
|
44
|
+
* The envelope is built around what the caller asked for rather than written over it: one
|
|
45
|
+
* request object is handed to several concurrent calls in more than one place, and those are
|
|
46
|
+
* different calls — sharing one identity would have all but the first refused as duplicates
|
|
47
|
+
* of it.
|
|
48
|
+
*/
|
|
49
|
+
const envelope = {
|
|
50
|
+
...asked,
|
|
51
|
+
// avoid validation on the recipient's side
|
|
52
|
+
authentic: true,
|
|
53
|
+
// an operation that takes no input still has to send an explicit null
|
|
54
|
+
input: request.input ?? null,
|
|
55
|
+
id: request.id ?? this.#identity(invocation),
|
|
56
|
+
/*
|
|
57
|
+
* What a receiver has already put on the request wins, and a service with no chain in
|
|
58
|
+
* scope starts one under its own name.
|
|
59
|
+
*/
|
|
60
|
+
trail: request.trail ?? invocation?.hops ?? service(this.#source),
|
|
61
|
+
// the caller may have attributed the call itself, as the node bridge does
|
|
62
|
+
source: request.source ?? this.#source
|
|
63
|
+
};
|
|
64
|
+
// nothing carries a key it has no value for onto the wire
|
|
65
|
+
if (envelope.source === undefined)
|
|
66
|
+
delete envelope.source;
|
|
67
|
+
if (envelope.trail === undefined)
|
|
68
|
+
delete envelope.trail;
|
|
69
|
+
if (readonly)
|
|
70
|
+
envelope.readonly = true;
|
|
71
|
+
this.#contract.fit(envelope);
|
|
72
|
+
const context = current();
|
|
73
|
+
if (context !== undefined)
|
|
74
|
+
envelope.telemetry = encode(context);
|
|
75
|
+
const reply = await this.#transmit(envelope, this.#terms(instance, options.timeout, options.signal));
|
|
76
|
+
if (reply === null)
|
|
77
|
+
return null;
|
|
78
|
+
else if (reply instanceof Readable)
|
|
79
|
+
return reply;
|
|
80
|
+
else {
|
|
81
|
+
if (reply.exception !== undefined)
|
|
82
|
+
throw reply.exception;
|
|
83
|
+
if (reply.error !== undefined)
|
|
84
|
+
return new RemoteError(reply.error);
|
|
85
|
+
else
|
|
86
|
+
return reply.output;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
explain() {
|
|
90
|
+
return this.#contract.discovery;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Derived where this process is serving a call, so that the same call served twice makes the
|
|
94
|
+
* same call here twice over and whatever it reaches refuses its own copy; minted where there
|
|
95
|
+
* is nothing to derive from, which is an entry point, or a caller from before identities.
|
|
96
|
+
*/
|
|
97
|
+
#identity(invocation) {
|
|
98
|
+
if (invocation?.id === undefined)
|
|
99
|
+
return newid();
|
|
100
|
+
return derive(invocation.id, this.#target, trail.ordinal(invocation, this.#target));
|
|
101
|
+
}
|
|
102
|
+
/** A call whose making contradicts what it calls is refused before anything is sent. */
|
|
103
|
+
#refuse(request, options, readonly) {
|
|
104
|
+
const { instance, task } = request;
|
|
105
|
+
const { timeout, signal } = options;
|
|
106
|
+
if (readonly && !this.#safe)
|
|
107
|
+
throw new SafetyException(`'${this.#target}' may change state, and this call may only read`);
|
|
108
|
+
if (this.#stateful && instance === undefined)
|
|
109
|
+
throw new RequestContractException(`'${this.#target}' is stateful, and a call to it names \`instance\``);
|
|
110
|
+
if (!this.#stateful && instance !== undefined)
|
|
111
|
+
throw new RequestContractException(`'${this.#target}' is stateless, and a call to it names no \`instance\``);
|
|
112
|
+
// a task is taken by whichever process is free, and a stateful operation is served
|
|
113
|
+
// under the name of one
|
|
114
|
+
if (this.#stateful && task === true)
|
|
115
|
+
throw new RequestContractException(`'${this.#target}' is stateful, and a call to it is no task`);
|
|
116
|
+
// nobody waits for a task, and it is made from wherever the queue is consumed
|
|
117
|
+
if (task === true && (timeout !== undefined || signal !== undefined))
|
|
118
|
+
throw new RequestContractException('A task names no `timeout` and no `signal`');
|
|
119
|
+
if (timeout !== undefined && !(Number.isFinite(timeout) && timeout > 0))
|
|
120
|
+
throw new RequestContractException('`timeout` is a positive number of milliseconds');
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* What the transmission is handed beside the envelope. An addressed call always waits for a set
|
|
124
|
+
* time — its caller's, or the context's — because nothing else ends a call to a process that has
|
|
125
|
+
* gone; an ordinary call waits for one only where its caller set it.
|
|
126
|
+
*/
|
|
127
|
+
#terms(instance, timeout, signal) {
|
|
128
|
+
const deadline = timeout ?? (this.#stateful ? addressed.timeout() : undefined);
|
|
129
|
+
if (instance === undefined && deadline === undefined && signal === undefined)
|
|
130
|
+
return undefined;
|
|
131
|
+
const signals = [];
|
|
132
|
+
if (signal !== undefined)
|
|
133
|
+
signals.push(signal);
|
|
134
|
+
if (deadline !== undefined)
|
|
135
|
+
signals.push(AbortSignal.timeout(deadline));
|
|
136
|
+
const terms = {};
|
|
137
|
+
if (instance !== undefined)
|
|
138
|
+
terms.instance = instance;
|
|
139
|
+
if (deadline !== undefined)
|
|
140
|
+
terms.timeout = deadline;
|
|
141
|
+
if (signals.length > 0)
|
|
142
|
+
terms.signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
|
|
143
|
+
return terms;
|
|
144
|
+
}
|
|
145
|
+
/** The reply, or *abandoned* once the caller has stopped waiting, however the wait ended. */
|
|
146
|
+
async #transmit(envelope, terms) {
|
|
147
|
+
const signal = terms?.signal;
|
|
148
|
+
// a call its caller stopped waiting for before it was made is handed to no binding
|
|
149
|
+
if (signal?.aborted === true)
|
|
150
|
+
throw abandoned(this.#target, signal);
|
|
151
|
+
return await waiting(this.#transmitter.request(envelope, terms), signal, this.#target);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/** Where a service calls from no invocation, the chain starts under the service's own name. */
|
|
155
|
+
function service(source) {
|
|
156
|
+
return source !== undefined && 'service' in source ? [source.service] : undefined;
|
|
157
|
+
}
|
|
158
|
+
// the remote error as a value: every property it carries, and nothing else enumerable
|
|
159
|
+
class RemoteError extends Error {
|
|
160
|
+
constructor(error) {
|
|
161
|
+
super();
|
|
162
|
+
Object.assign(this, error);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=call.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call.js","sourceRoot":"","sources":["../source/call.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Connector } from './connector.ts';
|
|
2
|
+
import type { Algorithm } from './types/bridges.ts';
|
|
3
|
+
export declare class Cascade extends Connector {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(bridges: Algorithm[], preflight?: Connector);
|
|
6
|
+
run(...args: [any, any?]): Promise<any>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Connector } from './connector.js';
|
|
2
|
+
export class Cascade extends Connector {
|
|
3
|
+
#last;
|
|
4
|
+
constructor(bridges, preflight) {
|
|
5
|
+
super();
|
|
6
|
+
// this.#bridges = bridges
|
|
7
|
+
this.#last = bridges[bridges.length - 1];
|
|
8
|
+
if (preflight === undefined)
|
|
9
|
+
this.depends(bridges);
|
|
10
|
+
else
|
|
11
|
+
this.depends(bridges).depends(preflight);
|
|
12
|
+
}
|
|
13
|
+
async run(...args) {
|
|
14
|
+
// const reply = {}
|
|
15
|
+
//
|
|
16
|
+
// for (const bridge of this.#bridges) {
|
|
17
|
+
// const partial = await bridge.execute(...args)
|
|
18
|
+
//
|
|
19
|
+
// if (partial.error) return { error: partial.error }
|
|
20
|
+
//
|
|
21
|
+
// merge(reply, partial)
|
|
22
|
+
// }
|
|
23
|
+
//
|
|
24
|
+
// return reply
|
|
25
|
+
return this.#last.execute(...args);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=cascade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cascade.js","sourceRoot":"","sources":["../source/cascade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAG1C,MAAM,OAAO,OAAQ,SAAQ,SAAS;IAC3B,KAAK,CAAW;IAEzB,YAAmB,OAAoB,EAAE,SAAqB;QAC5D,KAAK,EAAE,CAAA;QAEP,0BAA0B;QAC1B,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAExC,IAAI,SAAS,KAAK,SAAS;YAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;;YAC7C,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAC/C,CAAC;IAEM,KAAK,CAAC,GAAG,CAAC,GAAG,IAAiB;QACnC,mBAAmB;QACnB,EAAE;QACF,wCAAwC;QACxC,kDAAkD;QAClD,EAAE;QACF,uDAAuD;QACvD,EAAE;QACF,0BAA0B;QAC1B,IAAI;QACJ,EAAE;QACF,eAAe;QAEf,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;IACpC,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Connector } from './connector.ts';
|
|
2
|
+
import type { Locator } from './locator.ts';
|
|
3
|
+
import type { Envelope, Options, Request } from './types/request.ts';
|
|
4
|
+
/** What a component holds one of per endpoint: an operation, or the call that stands for it. */
|
|
5
|
+
export interface Invocable extends Connector {
|
|
6
|
+
invoke: (request: Envelope, options?: Options) => Promise<any>;
|
|
7
|
+
}
|
|
8
|
+
export declare class Component<O extends Invocable = Invocable> extends Connector {
|
|
9
|
+
#private;
|
|
10
|
+
readonly locator: Locator;
|
|
11
|
+
protected readonly operations: Record<string, O>;
|
|
12
|
+
protected kind: 'server' | 'client';
|
|
13
|
+
constructor(locator: Locator, operations: Record<string, O>);
|
|
14
|
+
invoke<T = any>(endpoint: string, request?: Request, options?: Options): Promise<T>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { console, current, decode, run } from 'openspan';
|
|
2
|
+
import { Connector } from './connector.js';
|
|
3
|
+
import { DisposedException, EndpointException, names, permanent } from './exceptions.js';
|
|
4
|
+
import * as measure from './measurements.js';
|
|
5
|
+
import * as trail from './trail.js';
|
|
6
|
+
/** The code a declared error refuses with, which its manifest bounds. */
|
|
7
|
+
function code(error) {
|
|
8
|
+
return String(error.code ?? 'UNDECLARED');
|
|
9
|
+
}
|
|
10
|
+
export class Component extends Connector {
|
|
11
|
+
locator;
|
|
12
|
+
operations;
|
|
13
|
+
kind = 'server';
|
|
14
|
+
/** span options per endpoint */
|
|
15
|
+
#spans = {};
|
|
16
|
+
/** what refuses a call that has been here already, as the environment states it */
|
|
17
|
+
#limits = trail.limits();
|
|
18
|
+
constructor(locator, operations) {
|
|
19
|
+
super();
|
|
20
|
+
this.locator = locator;
|
|
21
|
+
this.operations = operations;
|
|
22
|
+
Object.values(operations).forEach((operation) => this.depends(operation));
|
|
23
|
+
}
|
|
24
|
+
async invoke(endpoint, request, options) {
|
|
25
|
+
/*
|
|
26
|
+
* A component that has been taken down refuses to work. What reaches it here is something
|
|
27
|
+
* the component started and did not stop — an interval, a watcher, a promise nobody
|
|
28
|
+
* awaited — calling through a context whose tree is gone, and a resume builds another tree
|
|
29
|
+
* rather than reviving this one, so it is never coming back.
|
|
30
|
+
*
|
|
31
|
+
* The client side is left alone deliberately: a `Remote` is a client to a queue rather than
|
|
32
|
+
* to an instance of anything, so its being taken down says nothing about whether what it
|
|
33
|
+
* calls is there.
|
|
34
|
+
*/
|
|
35
|
+
if (this.disposed && this.kind === 'server')
|
|
36
|
+
throw new DisposedException(`'${this.locator.id}' has been taken down, and what reached it here was started by ` +
|
|
37
|
+
'something that outlived it');
|
|
38
|
+
if (!(endpoint in this.operations))
|
|
39
|
+
throw new EndpointException(`'${endpoint}' is not provided by '${this.locator.id}'`);
|
|
40
|
+
// if the request carries no telemetry, the trace starts here
|
|
41
|
+
const remote = request?.telemetry === undefined ? null : decode(request.telemetry);
|
|
42
|
+
const invocation = async () => this.#process(endpoint, request, options);
|
|
43
|
+
let task = invocation;
|
|
44
|
+
/*
|
|
45
|
+
* The hop is the server's alone. A `Remote` is a component too and names the very endpoint
|
|
46
|
+
* this one does, so counting it there as well would make the threshold depend on how many
|
|
47
|
+
* clients a call happened to cross — a different number for a local call, an HTTP one and a
|
|
48
|
+
* delayed one. An endpoint beginning with `.` is the runtime's own and is no hop at all.
|
|
49
|
+
*/
|
|
50
|
+
if (this.kind === 'server' && endpoint[0] !== '.') {
|
|
51
|
+
let hops;
|
|
52
|
+
try {
|
|
53
|
+
// the span's name is the hop's, and it is already built once per endpoint
|
|
54
|
+
hops = trail.extend(request?.trail, this.#span(endpoint).name, this.#limits);
|
|
55
|
+
}
|
|
56
|
+
catch (exception) {
|
|
57
|
+
console.error('Call chain refused', {
|
|
58
|
+
endpoint: `${this.locator.id}.${endpoint}`,
|
|
59
|
+
exception
|
|
60
|
+
});
|
|
61
|
+
// answered, not thrown: thrown, this would run into the broker library on the event
|
|
62
|
+
// path, and on the call path its code would survive only by `Exception` not being an
|
|
63
|
+
// `Error`. Answered, `Call` throws it into the caller as it does any other.
|
|
64
|
+
return { exception };
|
|
65
|
+
}
|
|
66
|
+
/*
|
|
67
|
+
* The identity is put in scope with the chain: an operation reaches neither, and the
|
|
68
|
+
* calls it makes derive their own from what it is serving. So is whether this request may
|
|
69
|
+
* only read, which is what every call the operation makes is then held to.
|
|
70
|
+
*/
|
|
71
|
+
const scope = { hops, id: request?.id };
|
|
72
|
+
if (request?.readonly === true)
|
|
73
|
+
scope.readonly = true;
|
|
74
|
+
task = async () => trail.follow(scope, invocation);
|
|
75
|
+
}
|
|
76
|
+
if (remote === null)
|
|
77
|
+
return task();
|
|
78
|
+
else
|
|
79
|
+
return run(remote, task);
|
|
80
|
+
}
|
|
81
|
+
async #process(endpoint, request, options) {
|
|
82
|
+
const measurements = this.kind === 'server' ? measure.operation : measure.call;
|
|
83
|
+
const labels = { component: this.locator.id, operation: endpoint };
|
|
84
|
+
measurements.inflight.add(1, labels);
|
|
85
|
+
try {
|
|
86
|
+
return await console.span(this.#span(endpoint), async () => {
|
|
87
|
+
const reply = await this.operations[endpoint].invoke(request, options);
|
|
88
|
+
if (reply?.error !== undefined && this.kind === 'server')
|
|
89
|
+
measure.operation.errors.add(1, { ...labels, code: code(reply.error) });
|
|
90
|
+
if (reply?.exception !== undefined) {
|
|
91
|
+
const span = current();
|
|
92
|
+
if (span !== undefined)
|
|
93
|
+
span.status = 'error';
|
|
94
|
+
this.#failed(labels, reply.exception);
|
|
95
|
+
console.error('Failed to execute operation', {
|
|
96
|
+
endpoint: `${this.locator.id}.${endpoint}`,
|
|
97
|
+
exception: reply.exception
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return reply;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
measurements.inflight.add(-1, labels);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* A refusal the caller sees is one the callee already counted, so only the server side counts
|
|
109
|
+
* an exception. `outcome` is what a receiver reads to choose between another attempt and the
|
|
110
|
+
* parking queue, which makes it two different incidents rather than one rate.
|
|
111
|
+
*/
|
|
112
|
+
#failed(labels, exception) {
|
|
113
|
+
if (this.kind !== 'server')
|
|
114
|
+
return;
|
|
115
|
+
const { code = 0 } = exception;
|
|
116
|
+
measure.operation.exceptions.add(1, {
|
|
117
|
+
...labels,
|
|
118
|
+
code: names[code] ?? String(code),
|
|
119
|
+
outcome: permanent(exception) ? 'permanent' : 'transient'
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The span of an endpoint never changes, so it is built once. Not in the constructor:
|
|
124
|
+
* `kind` is a field of the subclass, and those are assigned after this one is built.
|
|
125
|
+
*
|
|
126
|
+
*/
|
|
127
|
+
#span(endpoint) {
|
|
128
|
+
let options = this.#spans[endpoint];
|
|
129
|
+
if (options === undefined) {
|
|
130
|
+
const measurements = this.kind === 'server' ? measure.operation : measure.call;
|
|
131
|
+
options = {
|
|
132
|
+
name: `${this.locator.id}.${endpoint}`,
|
|
133
|
+
kind: this.kind,
|
|
134
|
+
measure: {
|
|
135
|
+
histogram: measurements.duration,
|
|
136
|
+
labels: { component: this.locator.id, operation: endpoint }
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
// the server span is emitted by the component itself, while the client span
|
|
140
|
+
// belongs to the calling service and inherits it from the context
|
|
141
|
+
if (this.kind === 'server')
|
|
142
|
+
options.service = this.locator.id;
|
|
143
|
+
this.#spans[endpoint] = options;
|
|
144
|
+
}
|
|
145
|
+
return options;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component.js","sourceRoot":"","sources":["../source/component.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { console } from 'openspan';
|
|
2
|
+
import { Connector } from './connector.js';
|
|
3
|
+
export class Composition extends Connector {
|
|
4
|
+
constructor(producers, receivers, tenants) {
|
|
5
|
+
super();
|
|
6
|
+
if (producers.length > 0)
|
|
7
|
+
this.depends(producers);
|
|
8
|
+
if (receivers.length > 0)
|
|
9
|
+
this.depends(receivers);
|
|
10
|
+
if (tenants.length > 0)
|
|
11
|
+
this.depends(tenants);
|
|
12
|
+
}
|
|
13
|
+
async open() {
|
|
14
|
+
console.info('Composition complete');
|
|
15
|
+
}
|
|
16
|
+
async dispose() {
|
|
17
|
+
console.info('Composition shutdown complete');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=composition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composition.js","sourceRoot":"","sources":["../source/composition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C,MAAM,OAAO,WAAY,SAAQ,SAAS;IACxC,YACE,SAAsB,EACtB,SAAsB,EACtB,OAAoB;QAEpB,KAAK,EAAE,CAAA;QAEP,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QACjD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QACjD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/C,CAAC;IAEkB,KAAK,CAAC,IAAI;QAC3B,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;IACtC,CAAC;IAEkB,KAAK,CAAC,OAAO;QAC9B,OAAO,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAA;IAC/C,CAAC;CACF"}
|