@toa.io/extensions.chronicles 0.0.0-stage → 1.0.0-alpha.333
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/LICENSE +22 -0
- package/components/chronicles.encounters/manifest.toa.yaml +108 -0
- package/components/chronicles.encounters/operations/anonymous.js +4 -0
- package/components/chronicles.encounters/operations/describe.js +4 -0
- package/components/chronicles.encounters/operations/identified.js +4 -0
- package/components/chronicles.encounters/types/index.d.ts +3 -0
- package/components/chronicles.encounters/types/toa.d.ts +36 -0
- package/components/chronicles.queries/manifest.toa.yaml +139 -0
- package/components/chronicles.queries/operations/define.js +3 -0
- package/components/chronicles.queries/operations/describe.js +3 -0
- package/components/chronicles.queries/operations/drop.js +3 -0
- package/components/chronicles.queries/operations/query.js +3 -0
- package/components/chronicles.queries/types/index.d.ts +3 -0
- package/components/chronicles.queries/types/toa.d.ts +49 -0
- package/components/chronicles.relay/manifest.toa.yaml +43 -0
- package/components/chronicles.relay/operations/encounter.js +4 -0
- package/components/chronicles.relay/operations/record.js +4 -0
- package/components/chronicles.relay/types/index.d.ts +3 -0
- package/components/chronicles.relay/types/toa.d.ts +24 -0
- package/guides/clickhouse.md +19 -0
- package/guides/log.md +52 -0
- package/package.json +39 -4
- package/readme.md +686 -0
- package/store/clickhouse.scope.sql +29 -0
- package/store/clickhouse.sql +99 -0
- package/transpiled/Client.d.ts +32 -0
- package/transpiled/Client.js +173 -0
- package/transpiled/Client.js.map +1 -0
- package/transpiled/Factory.d.ts +24 -0
- package/transpiled/Factory.js +62 -0
- package/transpiled/Factory.js.map +1 -0
- package/transpiled/Provider.d.ts +142 -0
- package/transpiled/Provider.js +4 -0
- package/transpiled/Provider.js.map +1 -0
- package/transpiled/Publisher.d.ts +50 -0
- package/transpiled/Publisher.js +169 -0
- package/transpiled/Publisher.js.map +1 -0
- package/transpiled/Reader.d.ts +28 -0
- package/transpiled/Reader.js +166 -0
- package/transpiled/Reader.js.map +1 -0
- package/transpiled/Recorder.d.ts +38 -0
- package/transpiled/Recorder.js +107 -0
- package/transpiled/Recorder.js.map +1 -0
- package/transpiled/Relay.d.ts +14 -0
- package/transpiled/Relay.js +27 -0
- package/transpiled/Relay.js.map +1 -0
- package/transpiled/Sender.d.ts +25 -0
- package/transpiled/Sender.js +86 -0
- package/transpiled/Sender.js.map +1 -0
- package/transpiled/Service.d.ts +26 -0
- package/transpiled/Service.js +70 -0
- package/transpiled/Service.js.map +1 -0
- package/transpiled/address.d.ts +7 -0
- package/transpiled/address.js +27 -0
- package/transpiled/address.js.map +1 -0
- package/transpiled/agent.d.ts +16 -0
- package/transpiled/agent.js +48 -0
- package/transpiled/agent.js.map +1 -0
- package/transpiled/clickhouse/Client.d.ts +35 -0
- package/transpiled/clickhouse/Client.js +71 -0
- package/transpiled/clickhouse/Client.js.map +1 -0
- package/transpiled/clickhouse/Provider.d.ts +35 -0
- package/transpiled/clickhouse/Provider.js +169 -0
- package/transpiled/clickhouse/Provider.js.map +1 -0
- package/transpiled/clickhouse/ddl.d.ts +9 -0
- package/transpiled/clickhouse/ddl.js +15 -0
- package/transpiled/clickhouse/ddl.js.map +1 -0
- package/transpiled/clickhouse/views.d.ts +11 -0
- package/transpiled/clickhouse/views.js +97 -0
- package/transpiled/clickhouse/views.js.map +1 -0
- package/transpiled/contract.d.ts +12 -0
- package/transpiled/contract.js +58 -0
- package/transpiled/contract.js.map +1 -0
- package/transpiled/index.d.ts +15 -0
- package/transpiled/index.js +2 -0
- package/transpiled/index.js.map +1 -0
- package/transpiled/settings.d.ts +13 -0
- package/transpiled/settings.js +48 -0
- package/transpiled/settings.js.map +1 -0
- package/transpiled/store.d.ts +5 -0
- package/transpiled/store.js +11 -0
- package/transpiled/store.js.map +1 -0
- package/README.md +0 -3
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { createConnection } from 'node:net';
|
|
2
|
+
import { connect } from 'comq';
|
|
3
|
+
import { console } from 'openspan';
|
|
4
|
+
import { Connector } from '@toa.io/core';
|
|
5
|
+
import { EXCHANGE } from '@toa.io/definitions/extensions.chronicles';
|
|
6
|
+
/**
|
|
7
|
+
* Rows to the broker of the log: each a JSON message to the exchange `chronicles` under the key of
|
|
8
|
+
* its table, with the scope of the context and when it expires. A publication resolves once the
|
|
9
|
+
* broker has confirmed it, which is what the caller acknowledges what it carried by.
|
|
10
|
+
*
|
|
11
|
+
* The connection is made by the first publication and not before, and nothing waits for it to
|
|
12
|
+
* start: while the broker is away, a publication waits for it, and what it carries waits, unacknowledged,
|
|
13
|
+
* where it came from.
|
|
14
|
+
*/
|
|
15
|
+
export class Publisher extends Connector {
|
|
16
|
+
url;
|
|
17
|
+
scope;
|
|
18
|
+
retention;
|
|
19
|
+
io;
|
|
20
|
+
opened;
|
|
21
|
+
/** aborted as the publisher stops: what waits for the broker then gives up, to be delivered again */
|
|
22
|
+
closing = new AbortController();
|
|
23
|
+
stopped = false;
|
|
24
|
+
/** where it publishes, which a publisher of other settings does not */
|
|
25
|
+
address;
|
|
26
|
+
// eslint-disable-next-line max-params
|
|
27
|
+
constructor(address, user, scope, retention) {
|
|
28
|
+
super();
|
|
29
|
+
this.address = address;
|
|
30
|
+
const url = new URL(address);
|
|
31
|
+
url.username = encodeURIComponent(user.username);
|
|
32
|
+
url.password = encodeURIComponent(user.password);
|
|
33
|
+
this.url = url.href;
|
|
34
|
+
this.scope = scope;
|
|
35
|
+
this.retention = retention;
|
|
36
|
+
}
|
|
37
|
+
async publish(rows, states = [], encounters = []) {
|
|
38
|
+
if (this.stopped)
|
|
39
|
+
throw new Error('The chronicles are stopping');
|
|
40
|
+
const io = await this.connection();
|
|
41
|
+
await Promise.all([
|
|
42
|
+
...rows.map(async (row) => await this.route(io, 'events', row, row.time)),
|
|
43
|
+
...states.map(async (state) => await this.route(io, 'states', state)),
|
|
44
|
+
...encounters.map(async (encounter) => await this.route(io, 'encounters', encounter, encounter.received))
|
|
45
|
+
]);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Fails what waits for the broker, and what is published from now on, so the service publishing
|
|
49
|
+
* through it is not held open by what would wait for the broker past the service's own end: it
|
|
50
|
+
* is delivered again, to this process or another.
|
|
51
|
+
*/
|
|
52
|
+
get done() {
|
|
53
|
+
return this.stopped;
|
|
54
|
+
}
|
|
55
|
+
stop() {
|
|
56
|
+
this.stopped = true;
|
|
57
|
+
this.closing.abort();
|
|
58
|
+
}
|
|
59
|
+
async open() {
|
|
60
|
+
this.stopped = false;
|
|
61
|
+
this.closing = new AbortController();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A connection still being made is not waited for — it may never be — but closed once it is,
|
|
65
|
+
* and what waits for it is failed, so it is delivered again, to this process or another.
|
|
66
|
+
*/
|
|
67
|
+
async close() {
|
|
68
|
+
const { io, opened } = this;
|
|
69
|
+
this.io = undefined;
|
|
70
|
+
this.opened = undefined;
|
|
71
|
+
this.stop();
|
|
72
|
+
if (opened !== undefined)
|
|
73
|
+
await opened.close();
|
|
74
|
+
else
|
|
75
|
+
void io?.then(async (late) => await late.close(), () => undefined);
|
|
76
|
+
}
|
|
77
|
+
async connection() {
|
|
78
|
+
this.io ??= reachable(this.url, this.closing.signal)
|
|
79
|
+
.then(async () => await connect(this.url))
|
|
80
|
+
.then((io) => {
|
|
81
|
+
this.opened = io;
|
|
82
|
+
return io;
|
|
83
|
+
}, (error) => {
|
|
84
|
+
this.io = undefined;
|
|
85
|
+
console.warn('Chronicles failed to reach their broker', {
|
|
86
|
+
error: error instanceof Error ? error.message : String(error)
|
|
87
|
+
});
|
|
88
|
+
throw error;
|
|
89
|
+
});
|
|
90
|
+
const { signal } = this.closing;
|
|
91
|
+
// a publication waits for the broker a while, and then fails, so what it carries is
|
|
92
|
+
// delivered again rather than held: a process that stops is not kept by one that never ends
|
|
93
|
+
return await new Promise((resolve, reject) => {
|
|
94
|
+
function away() {
|
|
95
|
+
reject(new Error('The broker of the chronicles is away'));
|
|
96
|
+
}
|
|
97
|
+
function closing() {
|
|
98
|
+
reject(new Error('The chronicles are closing'));
|
|
99
|
+
}
|
|
100
|
+
const timer = setTimeout(away, WAIT);
|
|
101
|
+
signal.addEventListener('abort', closing, { once: true });
|
|
102
|
+
this.io.then(resolve, reject).finally(() => {
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
signal.removeEventListener('abort', closing);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// eslint-disable-next-line max-params
|
|
109
|
+
async route(io, table, row, from) {
|
|
110
|
+
const body = message(row, this.scope, from === undefined ? null : expires(from, this.retention));
|
|
111
|
+
await io.route(EXCHANGE, table, body, 'application/json');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Resolves once the broker accepts a connection, trying again until it does or `signal` aborts.
|
|
116
|
+
* A connection is asked of comq only then: one it is asked for keeps trying for as long as it
|
|
117
|
+
* takes, and is no longer the publisher's to give up.
|
|
118
|
+
*/
|
|
119
|
+
async function reachable(url, signal) {
|
|
120
|
+
const { protocol, hostname, port } = new URL(url);
|
|
121
|
+
const target = { host: hostname, port: Number(port === '' ? DEFAULT[protocol] : port) };
|
|
122
|
+
while (!signal.aborted) {
|
|
123
|
+
const reached = await new Promise((resolve) => {
|
|
124
|
+
const socket = createConnection(target);
|
|
125
|
+
function settle(ok) {
|
|
126
|
+
socket.destroy();
|
|
127
|
+
resolve(ok);
|
|
128
|
+
}
|
|
129
|
+
socket.setTimeout(PROBE);
|
|
130
|
+
socket.once('connect', () => settle(true));
|
|
131
|
+
socket.once('timeout', () => settle(false));
|
|
132
|
+
socket.once('error', () => settle(false));
|
|
133
|
+
});
|
|
134
|
+
if (reached)
|
|
135
|
+
return;
|
|
136
|
+
await new Promise((resolve) => setTimeout(resolve, PROBE).unref());
|
|
137
|
+
}
|
|
138
|
+
throw new Error('The chronicles are closing');
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* A row as the store reads it: of a scope, its times in the store's format, and when it expires,
|
|
142
|
+
* where it does.
|
|
143
|
+
*/
|
|
144
|
+
export function message(row, scope, until) {
|
|
145
|
+
const body = { scope, ...row, time: timestamp(row.time) };
|
|
146
|
+
if ('received' in row)
|
|
147
|
+
body.received = timestamp(row.received);
|
|
148
|
+
if (until !== null)
|
|
149
|
+
body.expires = until;
|
|
150
|
+
return body;
|
|
151
|
+
}
|
|
152
|
+
/** When a row stops being kept: its time and the retention, or the end of the store's time. */
|
|
153
|
+
export function expires(from, retention) {
|
|
154
|
+
if (retention === undefined)
|
|
155
|
+
return FOREVER;
|
|
156
|
+
return timestamp(from + retention * DAY).slice(0, 19);
|
|
157
|
+
}
|
|
158
|
+
/** A `DateTime64(3)` as the store reads one without guessing: UTC, to the millisecond. */
|
|
159
|
+
export function timestamp(ms) {
|
|
160
|
+
return new Date(ms).toISOString().replace('T', ' ').replace('Z', '');
|
|
161
|
+
}
|
|
162
|
+
const DAY = 86_400_000;
|
|
163
|
+
/** milliseconds a publication waits for the broker */
|
|
164
|
+
const WAIT = 10_000;
|
|
165
|
+
/** milliseconds a try to reach the broker takes, and between two of them */
|
|
166
|
+
const PROBE = 1_000;
|
|
167
|
+
const DEFAULT = { 'amqp:': 5672, 'amqps:': 5671 };
|
|
168
|
+
const FOREVER = '2106-01-01 00:00:00';
|
|
169
|
+
//# sourceMappingURL=Publisher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Publisher.js","sourceRoot":"","sources":["../source/Publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,2CAA2C,CAAA;AAKpE;;;;;;;;GAQG;AACH,MAAM,OAAO,SAAU,SAAQ,SAAS;IACrB,GAAG,CAAQ;IACX,KAAK,CAAQ;IACb,SAAS,CAAoB;IACtC,EAAE,CAAc;IAChB,MAAM,CAAK;IAEnB,qGAAqG;IAC7F,OAAO,GAAG,IAAI,eAAe,EAAE,CAAA;IAC/B,OAAO,GAAG,KAAK,CAAA;IAEvB,uEAAuE;IACvD,OAAO,CAAQ;IAE/B,sCAAsC;IACtC,YAAmB,OAAe,EAAE,IAAU,EAAE,KAAa,EAAE,SAAkB;QAC/E,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QAEtB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAA;QAE5B,GAAG,CAAC,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAChD,GAAG,CAAC,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAEhD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,CAAA;QACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;IAC5B,CAAC;IAEM,KAAK,CAAC,OAAO,CAClB,IAAW,EACX,MAAM,GAAY,EAAE,EACpB,UAAU,GAAgB,EAAE;QAE5B,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;QAEhE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAA;QAElC,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YACzE,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACrE,GAAG,UAAU,CAAC,GAAG,CACf,KAAK,EAAE,SAAS,EAAE,EAAE,CAClB,MAAM,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,CAAC,QAAQ,CAAC,CACpE;SACF,CAAC,CAAA;IACJ,CAAC;IAED;;;;OAIG;IACH,IAAW,IAAI;QACb,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAEM,IAAI;QACT,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;IAEkB,KAAK,CAAC,IAAI;QAC3B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QACpB,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,EAAE,CAAA;IACtC,CAAC;IAED;;;OAGG;IACgB,KAAK,CAAC,KAAK;QAC5B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;QAE3B,IAAI,CAAC,EAAE,GAAG,SAAS,CAAA;QACnB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAA;QACvB,IAAI,CAAC,IAAI,EAAE,CAAA;QAEX,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;;YAE5C,KAAK,EAAE,EAAE,IAAI,CACX,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAClC,GAAG,EAAE,CAAC,SAAS,CAChB,CAAA;IACL,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC,EAAE,KAAK,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;aACjD,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;aACzC,IAAI,CACH,CAAC,EAAE,EAAE,EAAE;YACL,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;YAEhB,OAAO,EAAE,CAAA;QACX,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;YACjB,IAAI,CAAC,EAAE,GAAG,SAAS,CAAA;YAEnB,OAAO,CAAC,IAAI,CAAC,yCAAyC,EAAE;gBACtD,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC9D,CAAC,CAAA;YAEF,MAAM,KAAK,CAAA;QACb,CAAC,CACF,CAAA;QAEH,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAA;QAE/B,oFAAoF;QACpF,4FAA4F;QAC5F,OAAO,MAAM,IAAI,OAAO,CAAK,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC/C,SAAS,IAAI;gBACX,MAAM,CAAC,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC,CAAA;YAC3D,CAAC;YAED,SAAS,OAAO;gBACd,MAAM,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAA;YACjD,CAAC;YAED,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;YAEpC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;YAEzD,IAAI,CAAC,EAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;gBAC1C,YAAY,CAAC,KAAK,CAAC,CAAA;gBACnB,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YAC9C,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,sCAAsC;IAC9B,KAAK,CAAC,KAAK,CACjB,EAAM,EACN,KAAa,EACb,GAA4B,EAC5B,IAAa;QAEb,MAAM,IAAI,GAAG,OAAO,CAClB,GAAG,EACH,IAAI,CAAC,KAAK,EACV,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAC1D,CAAA;QAED,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAA;IAC3D,CAAC;CACF;AAED;;;;GAIG;AACH,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,MAAmB;IACvD,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;IACjD,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAA;IAEvF,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;YACrD,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;YAEvC,SAAS,MAAM,CAAC,EAAW;gBACzB,MAAM,CAAC,OAAO,EAAE,CAAA;gBAChB,OAAO,CAAC,EAAE,CAAC,CAAA;YACb,CAAC;YAED,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;YACxB,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;YAC1C,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;YAC3C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3C,CAAC,CAAC,CAAA;QAEF,IAAI,OAAO;YAAE,OAAM;QAEnB,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAA;IACpE,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO,CACrB,GAA4B,EAC5B,KAAa,EACb,KAAoB;IAEpB,MAAM,IAAI,GAA4B,EAAE,KAAK,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAA;IAElF,IAAI,UAAU,IAAI,GAAG;QAAE,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAE9D,IAAI,KAAK,KAAK,IAAI;QAAE,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;IAExC,OAAO,IAAI,CAAA;AACb,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,SAA6B;IACjE,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,OAAO,CAAA;IAE3C,OAAO,SAAS,CAAC,IAAI,GAAG,SAAS,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AACvD,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,SAAS,CAAC,EAAU;IAClC,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;AACtE,CAAC;AAED,MAAM,GAAG,GAAG,UAAU,CAAA;AAEtB,sDAAsD;AACtD,MAAM,IAAI,GAAG,MAAM,CAAA;AAEnB,4EAA4E;AAC5E,MAAM,KAAK,GAAG,KAAK,CAAA;AAEnB,MAAM,OAAO,GAA2B,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;AACzE,MAAM,OAAO,GAAG,qBAAqB,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Connector } from '@toa.io/core';
|
|
2
|
+
import type { Provider } from './Provider.ts';
|
|
3
|
+
import type { extensions } from '@toa.io/core/types';
|
|
4
|
+
import type { Settings } from '@toa.io/definitions/extensions.chronicles';
|
|
5
|
+
/**
|
|
6
|
+
* What `chronicles.queries` reads the log through: queries in the provider's dialect, views made
|
|
7
|
+
* from a statement the provider let a query run, and what the log holds — how it is read, what the
|
|
8
|
+
* components declare, what the context documents of encounters, and what the store has written.
|
|
9
|
+
*/
|
|
10
|
+
export declare class Reader extends Connector {
|
|
11
|
+
readonly name = "chronicles";
|
|
12
|
+
private readonly host;
|
|
13
|
+
private readonly provider;
|
|
14
|
+
private readonly settings;
|
|
15
|
+
private encounters?;
|
|
16
|
+
constructor(host: extensions.Host, provider: () => Provider, settings: () => Settings);
|
|
17
|
+
invoke(method: string, ...args: any[]): Promise<unknown>;
|
|
18
|
+
private describe;
|
|
19
|
+
private query;
|
|
20
|
+
private define;
|
|
21
|
+
private drop;
|
|
22
|
+
/**
|
|
23
|
+
* What the configuration of `chronicles.encounters` documents, asked of that component, which is
|
|
24
|
+
* in this service where the context serves encounters. Found on the first ask and not before: an
|
|
25
|
+
* aspect is made ahead of the components of its composition.
|
|
26
|
+
*/
|
|
27
|
+
private documented;
|
|
28
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { Connector, Locator, exceptions } from '@toa.io/core';
|
|
4
|
+
import { ENCOUNTERS, NAMESPACE } from '@toa.io/definitions/extensions.chronicles';
|
|
5
|
+
import { Refusal } from './Provider.js';
|
|
6
|
+
/**
|
|
7
|
+
* What `chronicles.queries` reads the log through: queries in the provider's dialect, views made
|
|
8
|
+
* from a statement the provider let a query run, and what the log holds — how it is read, what the
|
|
9
|
+
* components declare, what the context documents of encounters, and what the store has written.
|
|
10
|
+
*/
|
|
11
|
+
export class Reader extends Connector {
|
|
12
|
+
name = 'chronicles';
|
|
13
|
+
host;
|
|
14
|
+
provider;
|
|
15
|
+
settings;
|
|
16
|
+
encounters;
|
|
17
|
+
constructor(host, provider, settings) {
|
|
18
|
+
super();
|
|
19
|
+
this.host = host;
|
|
20
|
+
this.provider = provider;
|
|
21
|
+
this.settings = settings;
|
|
22
|
+
}
|
|
23
|
+
async invoke(method, ...args) {
|
|
24
|
+
switch (method) {
|
|
25
|
+
case 'describe':
|
|
26
|
+
return await this.describe();
|
|
27
|
+
case 'query':
|
|
28
|
+
return await this.query(args[0]);
|
|
29
|
+
case 'define':
|
|
30
|
+
return await this.define(args[0]);
|
|
31
|
+
case 'drop':
|
|
32
|
+
return await this.drop(args[0]);
|
|
33
|
+
default:
|
|
34
|
+
throw new exceptions.MisuseException(`Chronicles have no '${method}'`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async describe() {
|
|
38
|
+
const provider = this.provider();
|
|
39
|
+
const settings = this.settings();
|
|
40
|
+
const [written, kept, sent, views, documented] = await Promise.all([
|
|
41
|
+
provider.labels(),
|
|
42
|
+
provider.states(),
|
|
43
|
+
provider.encounters(),
|
|
44
|
+
provider.views(),
|
|
45
|
+
this.documented(settings)
|
|
46
|
+
]);
|
|
47
|
+
const declared = { ...settings.events, ...settings.facts };
|
|
48
|
+
const stated = Object.fromEntries(Object.entries(settings.states).map(([label, contract]) => [
|
|
49
|
+
component(label),
|
|
50
|
+
contract
|
|
51
|
+
]));
|
|
52
|
+
const labels = merge(written.map(({ label, ...stats }) => [label, stats]), Object.keys(declared)).map(([label, stats]) => ({
|
|
53
|
+
label,
|
|
54
|
+
...about(declared[label], provider),
|
|
55
|
+
...(stats ?? { rows: 0 })
|
|
56
|
+
}));
|
|
57
|
+
const states = merge(kept.map(({ component, ...stats }) => [component, stats]), Object.keys(stated)).map(([component, stats]) => ({
|
|
58
|
+
component,
|
|
59
|
+
...about(stated[component], provider),
|
|
60
|
+
...(stats ?? { entities: 0 })
|
|
61
|
+
}));
|
|
62
|
+
const encounters = merge(sent.map(({ name, ...stats }) => [name, stats]), Object.keys(documented)).map(([name, stats]) => {
|
|
63
|
+
const { description, fields: told = {} } = documented[name] ?? {};
|
|
64
|
+
const fields = (stats?.fields ?? []).map((field) => told[field.path] === undefined
|
|
65
|
+
? field
|
|
66
|
+
: { ...field, description: told[field.path] });
|
|
67
|
+
return {
|
|
68
|
+
name,
|
|
69
|
+
...(description === undefined ? {} : { description }),
|
|
70
|
+
...(stats ?? { rows: 0 }),
|
|
71
|
+
fields
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
return { guide: `${GUIDE}\n${provider.guide}`, labels, states, encounters, views };
|
|
75
|
+
}
|
|
76
|
+
async query(sql) {
|
|
77
|
+
return await refused(async () => await this.provider().query(statement(sql)));
|
|
78
|
+
}
|
|
79
|
+
async define(definition) {
|
|
80
|
+
const provider = this.provider();
|
|
81
|
+
const { name } = definition;
|
|
82
|
+
if (provider.tables.includes(name))
|
|
83
|
+
return new Error('RESERVED', {
|
|
84
|
+
cause: { message: `'${name}' is a table of the log` }
|
|
85
|
+
});
|
|
86
|
+
const select = statement(definition.sql);
|
|
87
|
+
const invalid = await refused(async () => await provider.validate(select));
|
|
88
|
+
if (invalid instanceof Error)
|
|
89
|
+
return invalid;
|
|
90
|
+
const views = await provider.views();
|
|
91
|
+
if (!views.some((view) => view.name === name) && views.length >= MAX_VIEWS)
|
|
92
|
+
return new Error('EXHAUSTED', {
|
|
93
|
+
cause: { message: `A context has at most ${MAX_VIEWS} views` }
|
|
94
|
+
});
|
|
95
|
+
const defined = await refused(async () => await provider.define({ ...definition, sql: select }));
|
|
96
|
+
return defined instanceof Error ? defined : undefined;
|
|
97
|
+
}
|
|
98
|
+
async drop(name) {
|
|
99
|
+
const provider = this.provider();
|
|
100
|
+
const views = await provider.views();
|
|
101
|
+
if (!views.some((view) => view.name === name))
|
|
102
|
+
return new Error('NOT_FOUND');
|
|
103
|
+
await provider.drop(name);
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* What the configuration of `chronicles.encounters` documents, asked of that component, which is
|
|
108
|
+
* in this service where the context serves encounters. Found on the first ask and not before: an
|
|
109
|
+
* aspect is made ahead of the components of its composition.
|
|
110
|
+
*/
|
|
111
|
+
async documented(settings) {
|
|
112
|
+
if (!settings.encounters)
|
|
113
|
+
return {};
|
|
114
|
+
this.encounters ??= (async () => {
|
|
115
|
+
const remote = await this.host.remote(LOCATOR, SOURCE);
|
|
116
|
+
this.depends(remote);
|
|
117
|
+
await remote.connect();
|
|
118
|
+
return remote;
|
|
119
|
+
})().catch((error) => {
|
|
120
|
+
this.encounters = undefined;
|
|
121
|
+
throw error;
|
|
122
|
+
});
|
|
123
|
+
const remote = await this.encounters;
|
|
124
|
+
return (await remote.invoke('describe', {}));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Of what was written and what is declared, by key, in order: a key declared and not yet written
|
|
129
|
+
* has no statistics, and one written and no longer declared has nothing else.
|
|
130
|
+
*/
|
|
131
|
+
function merge(written, declared) {
|
|
132
|
+
const by = new Map(written);
|
|
133
|
+
const keys = [...new Set([...by.keys(), ...declared])].sort();
|
|
134
|
+
return keys.map((key) => [key, by.get(key)]);
|
|
135
|
+
}
|
|
136
|
+
/** What a declaration says of a label or a state: its meaning, and its fields. */
|
|
137
|
+
function about(contract, provider) {
|
|
138
|
+
if (contract === undefined)
|
|
139
|
+
return {};
|
|
140
|
+
return {
|
|
141
|
+
description: contract.description,
|
|
142
|
+
fields: provider.fields(contract.properties)
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function component(label) {
|
|
146
|
+
return label.slice(0, label.lastIndexOf('.'));
|
|
147
|
+
}
|
|
148
|
+
/** One statement: a trailing semicolon is an agent's habit. */
|
|
149
|
+
function statement(sql) {
|
|
150
|
+
return sql.trim().replace(/;+$/, '').trim();
|
|
151
|
+
}
|
|
152
|
+
async function refused(fn) {
|
|
153
|
+
try {
|
|
154
|
+
return await fn();
|
|
155
|
+
}
|
|
156
|
+
catch (exception) {
|
|
157
|
+
if (exception instanceof Refusal)
|
|
158
|
+
return new Error('REFUSED', { cause: { message: exception.message } });
|
|
159
|
+
throw exception;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const LOCATOR = new Locator(ENCOUNTERS, NAMESPACE);
|
|
163
|
+
const SOURCE = { service: 'chronicles' };
|
|
164
|
+
const MAX_VIEWS = 50;
|
|
165
|
+
const GUIDE = readFileSync(resolve(import.meta.dirname, '../guides/log.md'), 'utf8');
|
|
166
|
+
//# sourceMappingURL=Reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Reader.js","sourceRoot":"","sources":["../source/Reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Connector } from '@toa.io/core';
|
|
2
|
+
import type { Publisher } from './Publisher.ts';
|
|
3
|
+
import type { Row, State } from './Provider.ts';
|
|
4
|
+
import type { Contract } from '@toa.io/definitions/extensions.chronicles';
|
|
5
|
+
import type { Message } from '@toa.io/core/types';
|
|
6
|
+
/**
|
|
7
|
+
* The consumer of one event the log is kept of: a row of `events` for an event a component declares
|
|
8
|
+
* under `events`, and a state for the one it declares its `state`. A message carries what the event
|
|
9
|
+
* rendered, its id and when the change was made, so what is said of the entity — which, its
|
|
10
|
+
* version — is read from the payload, where the entity as it stands carries `id` and `VERSION`;
|
|
11
|
+
* when, from the property the component names, or the message; and what is written of the payload
|
|
12
|
+
* is what the contract declares.
|
|
13
|
+
*/
|
|
14
|
+
export declare class Recorder extends Connector {
|
|
15
|
+
private readonly label;
|
|
16
|
+
private readonly component;
|
|
17
|
+
private readonly kind;
|
|
18
|
+
private readonly of;
|
|
19
|
+
private readonly publisher;
|
|
20
|
+
constructor(label: string, kind: Kind, of: Of, publisher: Publisher);
|
|
21
|
+
receive(message: Message): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
/** What a component declares of the payloads of a label. */
|
|
24
|
+
export interface Of {
|
|
25
|
+
contract: Contract;
|
|
26
|
+
/** the property that names whose a row is; `null` where none does */
|
|
27
|
+
identity: string | null;
|
|
28
|
+
/** the property that says when the change was made; `null` where none does */
|
|
29
|
+
timestamp: string | null;
|
|
30
|
+
}
|
|
31
|
+
export declare function row(label: string, component: string, message: Message, of: Of): Row;
|
|
32
|
+
/**
|
|
33
|
+
* The entity as its state event renders it. One that does not say which entity it is, and which
|
|
34
|
+
* version, cannot be kept, and no delivery of it will say otherwise: refused as a contract the
|
|
35
|
+
* component broke, so it is parked on its first delivery rather than retried.
|
|
36
|
+
*/
|
|
37
|
+
export declare function state(label: string, component: string, message: Message, of: Of): State;
|
|
38
|
+
export type Kind = 'event' | 'state';
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Connector, entities, exceptions } from '@toa.io/core';
|
|
2
|
+
import { Mismatch, project } from './contract.js';
|
|
3
|
+
/**
|
|
4
|
+
* The consumer of one event the log is kept of: a row of `events` for an event a component declares
|
|
5
|
+
* under `events`, and a state for the one it declares its `state`. A message carries what the event
|
|
6
|
+
* rendered, its id and when the change was made, so what is said of the entity — which, its
|
|
7
|
+
* version — is read from the payload, where the entity as it stands carries `id` and `VERSION`;
|
|
8
|
+
* when, from the property the component names, or the message; and what is written of the payload
|
|
9
|
+
* is what the contract declares.
|
|
10
|
+
*/
|
|
11
|
+
export class Recorder extends Connector {
|
|
12
|
+
label;
|
|
13
|
+
component;
|
|
14
|
+
kind;
|
|
15
|
+
of;
|
|
16
|
+
publisher;
|
|
17
|
+
// eslint-disable-next-line max-params
|
|
18
|
+
constructor(label, kind, of, publisher) {
|
|
19
|
+
super();
|
|
20
|
+
this.label = label;
|
|
21
|
+
this.component = label.slice(0, label.lastIndexOf('.'));
|
|
22
|
+
this.kind = kind;
|
|
23
|
+
this.of = of;
|
|
24
|
+
this.publisher = publisher;
|
|
25
|
+
}
|
|
26
|
+
async receive(message) {
|
|
27
|
+
if (this.kind === 'state')
|
|
28
|
+
await this.publisher.publish([], [state(this.label, this.component, message, this.of)]);
|
|
29
|
+
else
|
|
30
|
+
await this.publisher.publish([row(this.label, this.component, message, this.of)]);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// eslint-disable-next-line max-params
|
|
34
|
+
export function row(label, component, message, of) {
|
|
35
|
+
const payload = object(message.payload);
|
|
36
|
+
const { id, VERSION } = payload;
|
|
37
|
+
return {
|
|
38
|
+
// a message from outside Toa carries no id, and is then the same message by what it says
|
|
39
|
+
id: message.id ?? entities.derive(label, JSON.stringify(payload)),
|
|
40
|
+
label,
|
|
41
|
+
component,
|
|
42
|
+
time: when(payload, message, of.timestamp),
|
|
43
|
+
entity: typeof id === 'string' ? id : null,
|
|
44
|
+
version: typeof VERSION === 'number' ? VERSION : null,
|
|
45
|
+
identity: whose(payload, of.identity),
|
|
46
|
+
trace: message.telemetry ?? null,
|
|
47
|
+
payload: declared(label, payload, of.contract)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The entity as its state event renders it. One that does not say which entity it is, and which
|
|
52
|
+
* version, cannot be kept, and no delivery of it will say otherwise: refused as a contract the
|
|
53
|
+
* component broke, so it is parked on its first delivery rather than retried.
|
|
54
|
+
*/
|
|
55
|
+
// eslint-disable-next-line max-params
|
|
56
|
+
export function state(label, component, message, of) {
|
|
57
|
+
const payload = object(message.payload);
|
|
58
|
+
const { id, VERSION } = payload;
|
|
59
|
+
if (typeof id !== 'string' || typeof VERSION !== 'number')
|
|
60
|
+
throw new exceptions.EntityContractException(`The state '${label}' is an entity as it stands, and its payload carries no 'id' and 'VERSION'`);
|
|
61
|
+
return {
|
|
62
|
+
component,
|
|
63
|
+
entity: id,
|
|
64
|
+
version: VERSION,
|
|
65
|
+
identity: whose(payload, of.identity),
|
|
66
|
+
time: when(payload, message, of.timestamp),
|
|
67
|
+
payload: declared(label, payload, of.contract)
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* When the change was made: what the payload says in the property the component names, or else
|
|
72
|
+
* what the message says, which the process that made the change stamped as it made it. A message
|
|
73
|
+
* of a process from before messages said so says nothing, and is when it is taken.
|
|
74
|
+
*/
|
|
75
|
+
function when(payload, message, property) {
|
|
76
|
+
const said = property === null ? undefined : payload[property];
|
|
77
|
+
if (typeof said === 'number')
|
|
78
|
+
return said;
|
|
79
|
+
return message.time ?? Date.now();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* What the contract declares of a payload. One it does not admit is a contract the component broke,
|
|
83
|
+
* which no delivery will mend: refused, so it is parked on its first delivery.
|
|
84
|
+
*/
|
|
85
|
+
function declared(label, payload, contract) {
|
|
86
|
+
try {
|
|
87
|
+
return project(payload, contract.properties);
|
|
88
|
+
}
|
|
89
|
+
catch (exception) {
|
|
90
|
+
if (exception instanceof Mismatch)
|
|
91
|
+
throw new exceptions.EntityContractException(`The payload of '${label}' is not what its chronicles declare: ${exception.message}`);
|
|
92
|
+
throw exception;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** The identity a payload names in the property the component declares, where it is one. */
|
|
96
|
+
function whose(payload, property) {
|
|
97
|
+
if (property === null)
|
|
98
|
+
return null;
|
|
99
|
+
const value = payload[property];
|
|
100
|
+
return typeof value === 'string' ? value : null;
|
|
101
|
+
}
|
|
102
|
+
function object(payload) {
|
|
103
|
+
return typeof payload === 'object' && payload !== null && !Array.isArray(payload)
|
|
104
|
+
? payload
|
|
105
|
+
: { value: payload };
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=Recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Recorder.js","sourceRoot":"","sources":["../source/Recorder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Connector } from '@toa.io/core';
|
|
2
|
+
import type { Publisher } from './Publisher.ts';
|
|
3
|
+
/**
|
|
4
|
+
* What `chronicles.relay` publishes the tasks it is given through: a fact a component sent, and the
|
|
5
|
+
* encounters of a batch a client sent. A task is done once the broker has confirmed its rows. The
|
|
6
|
+
* publisher is the relay's own, closed with it: the component may be composed by another factory
|
|
7
|
+
* than the one of the service it runs in.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Relay extends Connector {
|
|
10
|
+
readonly name = "chronicles";
|
|
11
|
+
private readonly publisher;
|
|
12
|
+
constructor(publisher: Publisher);
|
|
13
|
+
invoke(method: string, ...args: any[]): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Connector, exceptions } from '@toa.io/core';
|
|
2
|
+
/**
|
|
3
|
+
* What `chronicles.relay` publishes the tasks it is given through: a fact a component sent, and the
|
|
4
|
+
* encounters of a batch a client sent. A task is done once the broker has confirmed its rows. The
|
|
5
|
+
* publisher is the relay's own, closed with it: the component may be composed by another factory
|
|
6
|
+
* than the one of the service it runs in.
|
|
7
|
+
*/
|
|
8
|
+
export class Relay extends Connector {
|
|
9
|
+
name = 'chronicles';
|
|
10
|
+
publisher;
|
|
11
|
+
constructor(publisher) {
|
|
12
|
+
super();
|
|
13
|
+
this.publisher = publisher;
|
|
14
|
+
this.depends(publisher);
|
|
15
|
+
}
|
|
16
|
+
async invoke(method, ...args) {
|
|
17
|
+
switch (method) {
|
|
18
|
+
case 'record':
|
|
19
|
+
return await this.publisher.publish([args[0]]);
|
|
20
|
+
case 'encounter':
|
|
21
|
+
return await this.publisher.publish([], [], args[0]);
|
|
22
|
+
default:
|
|
23
|
+
throw new exceptions.MisuseException(`Chronicles have no '${method}'`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=Relay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Relay.js","sourceRoot":"","sources":["../source/Relay.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAIpD;;;;;GAKG;AACH,MAAM,OAAO,KAAM,SAAQ,SAAS;IAClB,IAAI,GAAG,YAAY,CAAA;IAElB,SAAS,CAAW;IAErC,YAAmB,SAAoB;QACrC,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACzB,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,MAAc,EAAE,GAAG,IAAW;QAChD,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,QAAQ;gBACX,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAQ,CAAC,CAAC,CAAA;YACvD,KAAK,WAAW;gBACd,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAgB,CAAC,CAAA;YACrE;gBACE,MAAM,IAAI,UAAU,CAAC,eAAe,CAAC,uBAAuB,MAAM,GAAG,CAAC,CAAA;QAC1E,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Connector, Locator } from '@toa.io/core';
|
|
2
|
+
import type { Contract } from '@toa.io/definitions/extensions.chronicles';
|
|
3
|
+
import type { extensions } from '@toa.io/core/types';
|
|
4
|
+
/**
|
|
5
|
+
* `context.chronicles.send(name, payload, { identity })` — a fact that changes no state, written under
|
|
6
|
+
* `<component>.<name>`, of which what the component declares of it is sent. It is a task to the
|
|
7
|
+
* component that writes facts, so it resolves once the broker has it, and is kept until that
|
|
8
|
+
* component takes it.
|
|
9
|
+
*/
|
|
10
|
+
export declare class Sender extends Connector {
|
|
11
|
+
readonly name = "chronicles";
|
|
12
|
+
private readonly host;
|
|
13
|
+
private readonly locator;
|
|
14
|
+
private readonly facts;
|
|
15
|
+
private remote?;
|
|
16
|
+
/** `facts` are the contracts of the facts the component declares, by name */
|
|
17
|
+
constructor(host: extensions.Host, locator: Locator, facts: Record<string, Contract>);
|
|
18
|
+
invoke(method: string, ...args: any[]): Promise<void>;
|
|
19
|
+
private send;
|
|
20
|
+
/**
|
|
21
|
+
* Resolved on the first fact and not before: an aspect is made ahead of the components of its
|
|
22
|
+
* composition, and one that could not be found is looked for again by the next fact.
|
|
23
|
+
*/
|
|
24
|
+
private recorder;
|
|
25
|
+
}
|