@toa.io/core 1.0.0-alpha.31 → 1.0.0-alpha.310
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,57 @@
|
|
|
1
|
+
import { empty } from '@toa.io/generic';
|
|
2
|
+
import * as criteria from './query/criteria.js';
|
|
3
|
+
import * as options from './query/options.js';
|
|
4
|
+
const parse = { ...criteria, ...options };
|
|
5
|
+
/** Translates the query a request carries into the one a storage is given. */
|
|
6
|
+
export class Query {
|
|
7
|
+
#properties;
|
|
8
|
+
/** parsed criteria by their expression */
|
|
9
|
+
#asts = new Map();
|
|
10
|
+
constructor(properties) {
|
|
11
|
+
this.#properties = properties;
|
|
12
|
+
}
|
|
13
|
+
parse(query) {
|
|
14
|
+
const result = {};
|
|
15
|
+
const { id, ids, version, criteria, search, ...rest } = query;
|
|
16
|
+
const options = this.#options(rest);
|
|
17
|
+
if (id !== undefined)
|
|
18
|
+
result.id = id;
|
|
19
|
+
if (ids !== undefined)
|
|
20
|
+
result.ids = ids;
|
|
21
|
+
if (version !== undefined)
|
|
22
|
+
result.version = version;
|
|
23
|
+
if (criteria !== undefined)
|
|
24
|
+
result.criteria = this.#criteria(criteria);
|
|
25
|
+
if (search !== undefined)
|
|
26
|
+
result.search = search;
|
|
27
|
+
if (options !== undefined)
|
|
28
|
+
result.options = options;
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
#options(given) {
|
|
32
|
+
if (empty(given))
|
|
33
|
+
return undefined;
|
|
34
|
+
return parse.options(given, this.#properties);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Lexing an RSQL expression is the most expensive thing this class does, and the same
|
|
38
|
+
* expression arrives over and over: a route builds it from its own declaration and the
|
|
39
|
+
* request parameters. The tree is only read downstream — a storage builds a fresh query
|
|
40
|
+
* from it — so it is kept rather than parsed again.
|
|
41
|
+
*
|
|
42
|
+
* Expressions come from the client, hence the bound. An invalid one throws before it
|
|
43
|
+
* reaches the cache.
|
|
44
|
+
*/
|
|
45
|
+
#criteria(criteria) {
|
|
46
|
+
const known = this.#asts.get(criteria);
|
|
47
|
+
if (known !== undefined)
|
|
48
|
+
return known;
|
|
49
|
+
const ast = parse.criteria(criteria, this.#properties);
|
|
50
|
+
if (this.#asts.size >= LIMIT)
|
|
51
|
+
this.#asts.clear();
|
|
52
|
+
this.#asts.set(criteria, ast);
|
|
53
|
+
return ast;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const LIMIT = 1024;
|
|
57
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../source/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACvC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAA;AAC/C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA;AAK7C,MAAM,KAAK,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAA;AAEzC,8EAA8E;AAC9E,MAAM,OAAO,KAAK;IACP,WAAW,CAAY;IAEhC,0CAA0C;IACjC,KAAK,GAAG,IAAI,GAAG,EAAgB,CAAA;IAExC,YAAmB,UAAsB;QACvC,IAAI,CAAC,WAAW,GAAG,UAAU,CAAA;IAC/B,CAAC;IAEM,KAAK,CAAC,KAAgB;QAC3B,MAAM,MAAM,GAAW,EAAE,CAAA;QACzB,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAA;QAE7D,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAEnC,IAAI,EAAE,KAAK,SAAS;YAAE,MAAM,CAAC,EAAE,GAAG,EAAE,CAAA;QACpC,IAAI,GAAG,KAAK,SAAS;YAAE,MAAM,CAAC,GAAG,GAAG,GAAG,CAAA;QACvC,IAAI,OAAO,KAAK,SAAS;YAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAA;QACnD,IAAI,QAAQ,KAAK,SAAS;YAAE,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;QACtE,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAA;QAChD,IAAI,OAAO,KAAK,SAAS;YAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAA;QAEnD,OAAO,MAAM,CAAA;IACf,CAAC;IAED,QAAQ,CAAC,KAA0B;QACjC,IAAI,KAAK,CAAC,KAAK,CAAC;YAAE,OAAO,SAAS,CAAA;QAElC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;IAC/C,CAAC;IAED;;;;;;;;OAQG;IACH,SAAS,CAAC,QAAgB;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAEtC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAA;QAErC,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;QAEtD,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,KAAK;YAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;QAEhD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;QAE7B,OAAO,GAAG,CAAA;IACZ,CAAC;CACF;AAED,MAAM,KAAK,GAAG,IAAI,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Connector } from './connector.ts';
|
|
2
|
+
import type { Component } from './component.ts';
|
|
3
|
+
import type { Receiver as Bridge } from './types/bridges.ts';
|
|
4
|
+
import type { Message } from './types/message.ts';
|
|
5
|
+
import type { Source } from './types/request.ts';
|
|
6
|
+
export interface Definition {
|
|
7
|
+
conditioned?: boolean;
|
|
8
|
+
adaptive?: boolean;
|
|
9
|
+
operation: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
destination?: string;
|
|
12
|
+
arguments?: unknown[];
|
|
13
|
+
origin?: Source;
|
|
14
|
+
}
|
|
15
|
+
export declare class Receiver extends Connector {
|
|
16
|
+
#private;
|
|
17
|
+
constructor(definition: Definition, local: Component, bridge?: Bridge);
|
|
18
|
+
/** @hot */
|
|
19
|
+
receive(message: Message): Promise<void>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { console, decode, run } from 'openspan';
|
|
2
|
+
import { add } from '@toa.io/generic';
|
|
3
|
+
import { Connector } from './connector.js';
|
|
4
|
+
import * as trail from './trail.js';
|
|
5
|
+
export class Receiver extends Connector {
|
|
6
|
+
#conditioned;
|
|
7
|
+
#adaptive;
|
|
8
|
+
#endpoint;
|
|
9
|
+
#label;
|
|
10
|
+
#destination;
|
|
11
|
+
#arguments;
|
|
12
|
+
#origin;
|
|
13
|
+
#local;
|
|
14
|
+
#bridge;
|
|
15
|
+
#delivery;
|
|
16
|
+
#processing;
|
|
17
|
+
constructor(definition, local, bridge) {
|
|
18
|
+
super();
|
|
19
|
+
const { conditioned, adaptive, operation } = definition;
|
|
20
|
+
this.#conditioned = conditioned;
|
|
21
|
+
this.#adaptive = adaptive;
|
|
22
|
+
this.#endpoint = operation;
|
|
23
|
+
this.#label = definition.label ?? operation;
|
|
24
|
+
this.#destination = definition.destination ?? this.#label;
|
|
25
|
+
this.#arguments = definition.arguments;
|
|
26
|
+
this.#origin = definition.origin;
|
|
27
|
+
this.#local = local;
|
|
28
|
+
this.#bridge = bridge;
|
|
29
|
+
this.depends(local);
|
|
30
|
+
if (bridge !== undefined)
|
|
31
|
+
this.depends(bridge);
|
|
32
|
+
/*
|
|
33
|
+
* The delivery span is created on behalf of the messaging destination, so that
|
|
34
|
+
* each consumer forms its own complete producer/consumer pair, and service graphs
|
|
35
|
+
* display fan-out correctly: producer -> destination -> each consumer
|
|
36
|
+
* (Tempo pairs spans one-to-one, thus multiple consumers can not pair
|
|
37
|
+
* with a single producer span, see grafana/tempo#5408)
|
|
38
|
+
*/
|
|
39
|
+
this.#delivery = {
|
|
40
|
+
name: `${this.#label} deliver`,
|
|
41
|
+
kind: 'producer',
|
|
42
|
+
service: this.#destination,
|
|
43
|
+
attributes: { 'messaging.destination.name': this.#destination }
|
|
44
|
+
};
|
|
45
|
+
this.#processing = {
|
|
46
|
+
name: `${this.#label} process`,
|
|
47
|
+
kind: 'consumer',
|
|
48
|
+
service: local.locator.id,
|
|
49
|
+
attributes: { 'messaging.destination.name': this.#destination }
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** @hot */
|
|
53
|
+
async receive(message) {
|
|
54
|
+
/*
|
|
55
|
+
* `trail` is taken out by name rather than left to `add`, which leaves an array the
|
|
56
|
+
* request already has alone and shares the deserialized one by reference where it does
|
|
57
|
+
* not — and validates neither.
|
|
58
|
+
*/
|
|
59
|
+
const { payload, telemetry, id, trail: inbound, ...extensions } = message;
|
|
60
|
+
if (this.#conditioned === true && (await this.#bridge?.condition(payload)) === false)
|
|
61
|
+
return;
|
|
62
|
+
const request = await this.#request(payload);
|
|
63
|
+
add(request, extensions);
|
|
64
|
+
// set after `add`, so that a message field can not spoof the origin
|
|
65
|
+
if (this.#origin !== undefined)
|
|
66
|
+
request.source = this.#origin;
|
|
67
|
+
/*
|
|
68
|
+
* The message's identity is the request's. Not derived any further: a component declares at
|
|
69
|
+
* most one receiver per event, so two of its own cannot collide, and two components have
|
|
70
|
+
* collections of their own. A message from before this existed carries none, and the call
|
|
71
|
+
* this makes mints one — which is to say it is not deduplicated, as it is not today.
|
|
72
|
+
*/
|
|
73
|
+
if (id !== undefined)
|
|
74
|
+
request.id = id;
|
|
75
|
+
/*
|
|
76
|
+
* The event is a hop of its own. What an operator rewires to break a cycle is the
|
|
77
|
+
* subscription rather than the operation, so a chain that named only operations would not
|
|
78
|
+
* say how a component was re-entered. Refusing is left to `Component.invoke`, one hop
|
|
79
|
+
* later, which acquires and commits nothing before it.
|
|
80
|
+
*/
|
|
81
|
+
request.trail = [...trail.received(inbound), trail.event(this.#destination)];
|
|
82
|
+
// continue the trace from the producer span
|
|
83
|
+
const remote = telemetry === undefined ? null : decode(telemetry);
|
|
84
|
+
const task = async () => {
|
|
85
|
+
await this.#process(request);
|
|
86
|
+
};
|
|
87
|
+
if (remote === null)
|
|
88
|
+
await task();
|
|
89
|
+
else
|
|
90
|
+
await run(remote, task);
|
|
91
|
+
}
|
|
92
|
+
async #process(request) {
|
|
93
|
+
return console.span(this.#delivery, async () => console.span(this.#processing, async () => {
|
|
94
|
+
try {
|
|
95
|
+
await this.#local.invoke(this.#endpoint, request);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
console.error('Receiver error', {
|
|
99
|
+
component: this.#local.locator.id,
|
|
100
|
+
endpoint: this.#endpoint,
|
|
101
|
+
error
|
|
102
|
+
});
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
async #request(payload) {
|
|
108
|
+
return this.#adaptive === true
|
|
109
|
+
? await this.#bridge.request(payload, ...(this.#arguments ?? []))
|
|
110
|
+
: { input: payload };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=receiver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receiver.js","sourceRoot":"","sources":["../source/receiver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Connector } from './connector.ts';
|
|
2
|
+
/** What a reflection reads, once, as it connects. */
|
|
3
|
+
export type Source<T = any> = () => Promise<T>;
|
|
4
|
+
export declare class Reflection<T = any> extends Connector {
|
|
5
|
+
#private;
|
|
6
|
+
value: T | undefined;
|
|
7
|
+
constructor(source: Source<T>);
|
|
8
|
+
protected open(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Connector } from './connector.js';
|
|
2
|
+
export class Reflection extends Connector {
|
|
3
|
+
value;
|
|
4
|
+
#source;
|
|
5
|
+
constructor(source) {
|
|
6
|
+
super();
|
|
7
|
+
this.#source = source;
|
|
8
|
+
}
|
|
9
|
+
async open() {
|
|
10
|
+
this.value = await this.#source();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=reflection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reflection.js","sourceRoot":"","sources":["../source/reflection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAK1C,MAAM,OAAO,UAAoB,SAAQ,SAAS;IACzC,KAAK,CAAe;IAElB,OAAO,CAAW;IAE3B,YAAmB,MAAiB;QAClC,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;IACvB,CAAC;IAEkB,KAAK,CAAC,IAAI;QAC3B,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;IACnC,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Component } from './component.ts';
|
|
2
|
+
import type { Invocable } from './component.ts';
|
|
3
|
+
/** A call knows what its endpoint declares, which is what an explanation is read from. */
|
|
4
|
+
export interface Explicable extends Invocable {
|
|
5
|
+
explain(): any;
|
|
6
|
+
}
|
|
7
|
+
export declare class Remote extends Component<Explicable> {
|
|
8
|
+
protected kind: 'client';
|
|
9
|
+
explain(endpoint: string): any;
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Component } from './component.js';
|
|
2
|
+
import { EndpointException } from './exceptions.js';
|
|
3
|
+
export class Remote extends Component {
|
|
4
|
+
kind = 'client';
|
|
5
|
+
explain(endpoint) {
|
|
6
|
+
if (!(endpoint in this.operations))
|
|
7
|
+
throw new EndpointException(`'${endpoint}' is not provided by '${this.locator.id}'`);
|
|
8
|
+
return this.operations[endpoint].explain();
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../source/remote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAQnD,MAAM,OAAO,MAAO,SAAQ,SAAqB;IAC5B,IAAI,GAAG,QAAiB,CAAA;IAEpC,OAAO,CAAC,QAAgB;QAC7B,IAAI,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC;YAChC,MAAM,IAAI,iBAAiB,CAAC,IAAI,QAAQ,yBAAyB,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAA;QAEtF,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAA;IAC5C,CAAC;CACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether an operation of this type is incapable of changing the State. What a readonly request may
|
|
3
|
+
* reach, and nothing else; see `documentation/readonly.md`.
|
|
4
|
+
*
|
|
5
|
+
* Exhaustive on purpose, as the outcome of an exception code is: a type added later does not
|
|
6
|
+
* compile until it says which it is, because a type nobody classified would otherwise be reachable
|
|
7
|
+
* from a request that promised to read.
|
|
8
|
+
*/
|
|
9
|
+
const SAFE = {
|
|
10
|
+
transition: false,
|
|
11
|
+
observation: true,
|
|
12
|
+
assignment: false,
|
|
13
|
+
computation: true,
|
|
14
|
+
// the type for an operation that reaches outside; what it reaches is not the runtime's to read
|
|
15
|
+
effect: false,
|
|
16
|
+
// its scope is the driver's own handle, and the runtime sees nothing it does with one
|
|
17
|
+
unmanaged: false
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Takes a `string` because it comes off a manifest: an operation of a type this does not know is
|
|
21
|
+
* unsafe, which is what an endpoint nothing can classify has to be.
|
|
22
|
+
*/
|
|
23
|
+
export function safe(type) {
|
|
24
|
+
return SAFE[type] === true;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=safety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../source/safety.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,IAAI,GAA0B;IAClC,UAAU,EAAE,KAAK;IACjB,WAAW,EAAE,IAAI;IACjB,UAAU,EAAE,KAAK;IACjB,WAAW,EAAE,IAAI;IACjB,+FAA+F;IAC/F,MAAM,EAAE,KAAK;IACb,sFAAsF;IACtF,SAAS,EAAE,KAAK;CACjB,CAAA;AAED;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,IAAY;IAC/B,OAAO,IAAI,CAAC,IAAY,CAAC,KAAK,IAAI,CAAA;AACpC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { EntitySet } from './entities/set.ts';
|
|
2
|
+
import type { Readable } from 'node:stream';
|
|
3
|
+
import type { Factory } from './entities/factory.ts';
|
|
4
|
+
import type { Entity } from './entities/entity.ts';
|
|
5
|
+
import type { Changeset } from './entities/changeset.ts';
|
|
6
|
+
import type { Outbox } from './outbox.ts';
|
|
7
|
+
import type { Call } from './types/inbox.ts';
|
|
8
|
+
import type { Query, Record, Storage } from './types/storages.ts';
|
|
9
|
+
/**
|
|
10
|
+
* What an operation acquires and commits. One method per scope a manifest may declare, which
|
|
11
|
+
* is how an operation reaches the one it was declared with.
|
|
12
|
+
*/
|
|
13
|
+
export declare class State {
|
|
14
|
+
#private;
|
|
15
|
+
readonly storage: Storage;
|
|
16
|
+
constructor(storage: Storage, entities: Factory, outbox: Outbox | undefined, associated?: boolean);
|
|
17
|
+
init(id?: string): Entity;
|
|
18
|
+
fit(values: object): void;
|
|
19
|
+
/** scope `object` */
|
|
20
|
+
object(query: Query, mutable?: boolean): Promise<Entity | null>;
|
|
21
|
+
/** scope `objects` */
|
|
22
|
+
objects(query: Query, mutable?: boolean): Promise<EntitySet>;
|
|
23
|
+
/** scope `stream` */
|
|
24
|
+
stream(query: Query): Promise<Readable>;
|
|
25
|
+
/** scope `changeset` */
|
|
26
|
+
changeset(query: Query): Changeset;
|
|
27
|
+
/** scope `none`: an operation that acquires nothing still asks for its scope */
|
|
28
|
+
none(): null;
|
|
29
|
+
/** get-or-create, in one indivisible step */
|
|
30
|
+
/** what the call under this identity answered, or `null` where it was never made */
|
|
31
|
+
recall(id: string): Promise<object | null>;
|
|
32
|
+
ensure(query: Query | undefined, properties: object, input?: object, call?: Call): Promise<Entity>;
|
|
33
|
+
commit(state: Entity | EntitySet, input?: object, call?: Call): Promise<boolean>;
|
|
34
|
+
massCommit(state: EntitySet, input?: object): Promise<boolean>;
|
|
35
|
+
apply(state: Changeset, input?: object, call?: Call): Promise<Record>;
|
|
36
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { EntitySet } from './entities/set.js';
|
|
2
|
+
import { StatePreconditionException, StateNotFoundException } from './exceptions.js';
|
|
3
|
+
/**
|
|
4
|
+
* What an operation acquires and commits. One method per scope a manifest may declare, which
|
|
5
|
+
* is how an operation reaches the one it was declared with.
|
|
6
|
+
*/
|
|
7
|
+
export class State {
|
|
8
|
+
storage;
|
|
9
|
+
#entities;
|
|
10
|
+
#outbox;
|
|
11
|
+
/** whether an entity exists by virtue of the identity it is looked up by */
|
|
12
|
+
#associated;
|
|
13
|
+
// eslint-disable-next-line max-params
|
|
14
|
+
constructor(storage, entities, outbox, associated) {
|
|
15
|
+
this.storage = storage;
|
|
16
|
+
this.#entities = entities;
|
|
17
|
+
this.#outbox = outbox;
|
|
18
|
+
this.#associated = associated === true;
|
|
19
|
+
}
|
|
20
|
+
init(id) {
|
|
21
|
+
return this.#entities.init(id);
|
|
22
|
+
}
|
|
23
|
+
fit(values) {
|
|
24
|
+
this.#entities.fit(values);
|
|
25
|
+
}
|
|
26
|
+
/** scope `object` */
|
|
27
|
+
async object(query, mutable = true) {
|
|
28
|
+
const record = await this.storage.get(query);
|
|
29
|
+
if (record !== null)
|
|
30
|
+
return this.#entities.object(record, mutable);
|
|
31
|
+
// an associated entity is whatever the identity it is looked up by names, so a miss on
|
|
32
|
+
// that identity alone is a blank rather than an absence
|
|
33
|
+
if (this.#associated &&
|
|
34
|
+
query.id !== undefined &&
|
|
35
|
+
query.criteria === undefined &&
|
|
36
|
+
query.version === undefined)
|
|
37
|
+
return this.init(query.id);
|
|
38
|
+
if (query.version !== undefined)
|
|
39
|
+
throw new StatePreconditionException();
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
/** scope `objects` */
|
|
43
|
+
async objects(query, mutable = true) {
|
|
44
|
+
const recordset = await this.storage.find(query);
|
|
45
|
+
const ids = query.ids;
|
|
46
|
+
const missing = this.#associated && ids !== undefined && recordset.length < ids.length;
|
|
47
|
+
const init = missing
|
|
48
|
+
? ids.filter((id) => !recordset.some((record) => record.id === id))
|
|
49
|
+
: undefined;
|
|
50
|
+
return this.#entities.objects(recordset, init, mutable);
|
|
51
|
+
}
|
|
52
|
+
/** scope `stream` */
|
|
53
|
+
async stream(query) {
|
|
54
|
+
return this.storage.stream(query);
|
|
55
|
+
}
|
|
56
|
+
/** scope `changeset` */
|
|
57
|
+
changeset(query) {
|
|
58
|
+
return this.#entities.changeset(query);
|
|
59
|
+
}
|
|
60
|
+
/** scope `none`: an operation that acquires nothing still asks for its scope */
|
|
61
|
+
none() {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
/** get-or-create, in one indivisible step */
|
|
65
|
+
/** what the call under this identity answered, or `null` where it was never made */
|
|
66
|
+
async recall(id) {
|
|
67
|
+
return (await this.storage.inbox?.recall(id)) ?? null;
|
|
68
|
+
}
|
|
69
|
+
// eslint-disable-next-line max-params
|
|
70
|
+
async ensure(query, properties, input, call) {
|
|
71
|
+
const object = this.#entities.init();
|
|
72
|
+
const blank = object.get();
|
|
73
|
+
Object.assign(blank, properties);
|
|
74
|
+
object.set(blank);
|
|
75
|
+
const row = this.#outbox?.row(object.event(input));
|
|
76
|
+
const record = await this.storage.ensure(query, properties, object.get(), row, call);
|
|
77
|
+
// whatever came back under another id was already there, and an effect never commits it
|
|
78
|
+
if (record.id !== blank.id)
|
|
79
|
+
return this.#entities.object(record, NOT_MUTABLE);
|
|
80
|
+
await this.#publish(row);
|
|
81
|
+
return object;
|
|
82
|
+
}
|
|
83
|
+
async commit(state, input, call) {
|
|
84
|
+
if (state instanceof EntitySet)
|
|
85
|
+
return this.massCommit(state, input);
|
|
86
|
+
// the row is built before the write so that the storage can commit it in the same
|
|
87
|
+
// transaction, closing the window this used to have
|
|
88
|
+
const row = this.#outbox?.row(state.event(input));
|
|
89
|
+
const ok = await this.storage.store(state.get(), row, call);
|
|
90
|
+
if (ok)
|
|
91
|
+
await this.#publish(row);
|
|
92
|
+
return ok;
|
|
93
|
+
}
|
|
94
|
+
async massCommit(state, input) {
|
|
95
|
+
const outbox = this.#outbox;
|
|
96
|
+
const rows = outbox === undefined
|
|
97
|
+
? undefined
|
|
98
|
+
: state.events(input).map((event) => outbox.row(event));
|
|
99
|
+
const ok = await this.storage.massStore(state.get(), rows);
|
|
100
|
+
if (ok && rows !== undefined)
|
|
101
|
+
await Promise.all(rows.map(async (row) => this.#publish(row)));
|
|
102
|
+
return ok;
|
|
103
|
+
}
|
|
104
|
+
async apply(state, input, call) {
|
|
105
|
+
// an assignment's images are the write's own, so the storage fills them in
|
|
106
|
+
const row = this.#outbox?.row({ input });
|
|
107
|
+
const result = await this.storage.upsert(state.query, state.export(), row, call);
|
|
108
|
+
if (result === null)
|
|
109
|
+
throw state.query.version === undefined
|
|
110
|
+
? new StateNotFoundException()
|
|
111
|
+
: new StatePreconditionException();
|
|
112
|
+
if (row !== undefined) {
|
|
113
|
+
// a storage that does not know how leaves the event with what it was given
|
|
114
|
+
row.event.state ??= result;
|
|
115
|
+
row.event.origin ??= null;
|
|
116
|
+
await this.#publish(row);
|
|
117
|
+
}
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Without a durable outbox this is the emission itself, and the operation waits for it;
|
|
122
|
+
* with one the row is already committed and this returns at once.
|
|
123
|
+
*/
|
|
124
|
+
async #publish(row) {
|
|
125
|
+
if (row !== undefined)
|
|
126
|
+
await this.#outbox?.publish(row);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** an effect never commits what `ensure` hands it, see `Effect` */
|
|
130
|
+
const NOT_MUTABLE = false;
|
|
131
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../source/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** What one invocation carries for the calls it makes. */
|
|
2
|
+
export interface Invocation {
|
|
3
|
+
/** the hops it came by, oldest first, ending with its own */
|
|
4
|
+
hops: string[];
|
|
5
|
+
/**
|
|
6
|
+
* The identity of the request being served. Absent where the caller stamped none, which is a
|
|
7
|
+
* caller from before this existed; a call made under one mints its own identity instead.
|
|
8
|
+
*/
|
|
9
|
+
id?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Whether what it may reach is a safe operation and nothing else. Carried onto every call it
|
|
12
|
+
* makes, and never dropped: the request that arrived said so, and so does every one below it.
|
|
13
|
+
*/
|
|
14
|
+
readonly?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* How many calls this invocation has already made to each endpoint. Two calls to one endpoint
|
|
17
|
+
* are two calls, and their identities have to say so — without this an operation looping over
|
|
18
|
+
* five items would make one identity five times and have four of them refused.
|
|
19
|
+
*
|
|
20
|
+
* Made where the first call is made: most operations make none.
|
|
21
|
+
*/
|
|
22
|
+
calls?: Map<string, number>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* How many times one hop may appear before the call is refused, and how long a chain may grow
|
|
26
|
+
* at all. Repetition is the signal and names the cycle; depth is the backstop for a chain that
|
|
27
|
+
* grows without repeating a hop, and it is what bounds the array on the wire.
|
|
28
|
+
*/
|
|
29
|
+
export interface Limits {
|
|
30
|
+
repeats: number;
|
|
31
|
+
depth: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* What the environment says, read where a component is built rather than once for the process,
|
|
35
|
+
* as the outbox reads its own — so a composition booted after a variable was set sees it.
|
|
36
|
+
*
|
|
37
|
+
* `TOA_TRAIL_REPEATS=0` refuses nothing: the chain is still stamped, carried and bounded. It is
|
|
38
|
+
* the off switch, and it exists because this refuses calls an application may be making today —
|
|
39
|
+
* a handshake written as `a > b > a > b > a` is three occurrences of one hop. A breaker with no
|
|
40
|
+
* way to open it is itself the outage.
|
|
41
|
+
*/
|
|
42
|
+
export declare function limits(): Limits;
|
|
43
|
+
/** The invocation running now, where there is one. */
|
|
44
|
+
export declare function current(): Invocation | undefined;
|
|
45
|
+
/** Runs `task` as the invocation the chain now ends with. */
|
|
46
|
+
export declare function follow<T>(invocation: Invocation, task: () => Promise<T>): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* The ordinal of the call `invocation` is about to make to `endpoint`, counting from zero, and
|
|
49
|
+
* counts it. Read once per call, on the caller's own path, which is where the order is the order
|
|
50
|
+
* the algorithm made them in.
|
|
51
|
+
*/
|
|
52
|
+
export declare function ordinal(invocation: Invocation, endpoint: string): number;
|
|
53
|
+
/**
|
|
54
|
+
* The chain this hop makes, or a raise where it is one hop too many: a hop already taken
|
|
55
|
+
* `repeats` times is a cycle, and a chain past `depth` is one nothing meant to make. Both are
|
|
56
|
+
* permanent, so what hits one is set aside rather than tried again into the same loop.
|
|
57
|
+
*
|
|
58
|
+
* The chain is copied rather than appended to, which is what makes it a path down the call
|
|
59
|
+
* tree rather than a log of everything that happened — an operation calling one endpoint fifty
|
|
60
|
+
* times makes fifty chains of one hop, not one chain of fifty.
|
|
61
|
+
*/
|
|
62
|
+
export declare function extend(inbound: unknown, hop: string, limits: Limits): string[];
|
|
63
|
+
/**
|
|
64
|
+
* How an event is named in a chain. The sigil is what tells it from an operation: the two are
|
|
65
|
+
* the same shape, a component may declare one of each under a single name, and `sync` is both
|
|
66
|
+
* the event every component inherits and an ordinary name for an operation.
|
|
67
|
+
*
|
|
68
|
+
* What an operator rewires to break a cycle is the subscription rather than the operation, so a
|
|
69
|
+
* chain that named only operations would not say how a component was re-entered.
|
|
70
|
+
*/
|
|
71
|
+
export declare function event(destination: string): string;
|
|
72
|
+
/**
|
|
73
|
+
* What came off the wire, as a chain and nothing else. Neither the request contract nor a
|
|
74
|
+
* message validates this — a request is not validated at all once it is `authentic` — so a
|
|
75
|
+
* malformed one would otherwise become a `TypeError` where a named exception was contracted
|
|
76
|
+
* for. Bounding it is `extend`'s, one hop later, which is the only place the limits are known.
|
|
77
|
+
*/
|
|
78
|
+
export declare function received(value: unknown): string[];
|