@toa.io/core 1.0.0-alpha.3 → 1.0.0-alpha.300

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.
Files changed (256) hide show
  1. package/package.json +28 -12
  2. package/transpiled/abandon.d.ts +9 -0
  3. package/transpiled/abandon.js +37 -0
  4. package/transpiled/abandon.js.map +1 -0
  5. package/transpiled/assignment.d.ts +6 -0
  6. package/transpiled/assignment.js +25 -0
  7. package/transpiled/assignment.js.map +1 -0
  8. package/transpiled/call.d.ts +10 -0
  9. package/transpiled/call.js +146 -0
  10. package/transpiled/call.js.map +1 -0
  11. package/transpiled/cascade.d.ts +7 -0
  12. package/transpiled/cascade.js +28 -0
  13. package/transpiled/cascade.js.map +1 -0
  14. package/transpiled/component.d.ts +15 -0
  15. package/transpiled/component.js +93 -0
  16. package/transpiled/component.js.map +1 -0
  17. package/transpiled/composition.d.ts +6 -0
  18. package/transpiled/composition.js +23 -0
  19. package/transpiled/composition.js.map +1 -0
  20. package/transpiled/connector.d.ts +54 -0
  21. package/transpiled/connector.js +193 -0
  22. package/transpiled/connector.js.map +1 -0
  23. package/transpiled/context.d.ts +25 -0
  24. package/transpiled/context.js +55 -0
  25. package/transpiled/context.js.map +1 -0
  26. package/transpiled/contract/contract.d.ts +10 -0
  27. package/transpiled/contract/contract.js +14 -0
  28. package/transpiled/contract/contract.js.map +1 -0
  29. package/transpiled/contract/index.d.ts +2 -0
  30. package/transpiled/contract/index.js +3 -0
  31. package/transpiled/contract/index.js.map +1 -0
  32. package/transpiled/contract/reply.d.ts +7 -0
  33. package/transpiled/contract/reply.js +48 -0
  34. package/transpiled/contract/reply.js.map +1 -0
  35. package/transpiled/contract/request.d.ts +39 -0
  36. package/transpiled/contract/request.js +111 -0
  37. package/transpiled/contract/request.js.map +1 -0
  38. package/transpiled/contract/schemas.d.ts +4 -0
  39. package/transpiled/contract/schemas.js +36 -0
  40. package/transpiled/contract/schemas.js.map +1 -0
  41. package/transpiled/discovery.d.ts +19 -0
  42. package/transpiled/discovery.js +52 -0
  43. package/transpiled/discovery.js.map +1 -0
  44. package/transpiled/effect.d.ts +5 -0
  45. package/transpiled/effect.js +11 -0
  46. package/transpiled/effect.js.map +1 -0
  47. package/transpiled/emission.d.ts +10 -0
  48. package/transpiled/emission.js +16 -0
  49. package/transpiled/emission.js.map +1 -0
  50. package/transpiled/entities/changeset.d.ts +10 -0
  51. package/transpiled/entities/changeset.js +27 -0
  52. package/transpiled/entities/changeset.js.map +1 -0
  53. package/transpiled/entities/entity.d.ts +19 -0
  54. package/transpiled/entities/entity.js +137 -0
  55. package/transpiled/entities/entity.js.map +1 -0
  56. package/transpiled/entities/factory.d.ts +27 -0
  57. package/transpiled/entities/factory.js +38 -0
  58. package/transpiled/entities/factory.js.map +1 -0
  59. package/transpiled/entities/index.d.ts +5 -0
  60. package/transpiled/entities/index.js +6 -0
  61. package/transpiled/entities/index.js.map +1 -0
  62. package/transpiled/entities/newid.d.ts +10 -0
  63. package/transpiled/entities/newid.js +35 -0
  64. package/transpiled/entities/newid.js.map +1 -0
  65. package/transpiled/entities/set.d.ts +10 -0
  66. package/transpiled/entities/set.js +19 -0
  67. package/transpiled/entities/set.js.map +1 -0
  68. package/transpiled/event.d.ts +14 -0
  69. package/transpiled/event.js +51 -0
  70. package/transpiled/event.js.map +1 -0
  71. package/transpiled/exceptions.d.ts +89 -0
  72. package/transpiled/exceptions.js +180 -0
  73. package/transpiled/exceptions.js.map +1 -0
  74. package/transpiled/exposition.d.ts +18 -0
  75. package/transpiled/exposition.js +18 -0
  76. package/transpiled/exposition.js.map +1 -0
  77. package/transpiled/guard.d.ts +7 -0
  78. package/transpiled/guard.js +12 -0
  79. package/transpiled/guard.js.map +1 -0
  80. package/transpiled/index.d.ts +37 -0
  81. package/transpiled/index.js +31 -0
  82. package/transpiled/index.js.map +1 -0
  83. package/transpiled/instance.d.ts +10 -0
  84. package/transpiled/instance.js +30 -0
  85. package/transpiled/instance.js.map +1 -0
  86. package/transpiled/locator.d.ts +12 -0
  87. package/transpiled/locator.js +32 -0
  88. package/transpiled/locator.js.map +1 -0
  89. package/transpiled/observation.d.ts +5 -0
  90. package/transpiled/observation.js +12 -0
  91. package/transpiled/observation.js.map +1 -0
  92. package/transpiled/operation.d.ts +67 -0
  93. package/transpiled/operation.js +127 -0
  94. package/transpiled/operation.js.map +1 -0
  95. package/transpiled/outbox.d.ts +45 -0
  96. package/transpiled/outbox.js +430 -0
  97. package/transpiled/outbox.js.map +1 -0
  98. package/transpiled/query/criteria.d.ts +6 -0
  99. package/transpiled/query/criteria.js +74 -0
  100. package/transpiled/query/criteria.js.map +1 -0
  101. package/transpiled/query/options.d.ts +3 -0
  102. package/transpiled/query/options.js +27 -0
  103. package/transpiled/query/options.js.map +1 -0
  104. package/transpiled/query.d.ts +9 -0
  105. package/transpiled/query.js +57 -0
  106. package/transpiled/query.js.map +1 -0
  107. package/transpiled/receiver.d.ts +20 -0
  108. package/transpiled/receiver.js +113 -0
  109. package/transpiled/receiver.js.map +1 -0
  110. package/transpiled/reflection.d.ts +9 -0
  111. package/transpiled/reflection.js +13 -0
  112. package/transpiled/reflection.js.map +1 -0
  113. package/transpiled/remote.d.ts +10 -0
  114. package/transpiled/remote.js +11 -0
  115. package/transpiled/remote.js.map +1 -0
  116. package/transpiled/state.d.ts +36 -0
  117. package/transpiled/state.js +131 -0
  118. package/transpiled/state.js.map +1 -0
  119. package/transpiled/trail.d.ts +71 -0
  120. package/transpiled/trail.js +110 -0
  121. package/transpiled/trail.js.map +1 -0
  122. package/transpiled/transition.d.ts +14 -0
  123. package/transpiled/transition.js +51 -0
  124. package/transpiled/transition.js.map +1 -0
  125. package/transpiled/transmission.d.ts +8 -0
  126. package/transpiled/transmission.js +30 -0
  127. package/transpiled/transmission.js.map +1 -0
  128. package/transpiled/types/atomicity.d.ts +56 -0
  129. package/transpiled/types/atomicity.js +2 -0
  130. package/transpiled/types/atomicity.js.map +1 -0
  131. package/transpiled/types/bindings.d.ts +77 -0
  132. package/transpiled/types/bindings.js +2 -0
  133. package/transpiled/types/bindings.js.map +1 -0
  134. package/transpiled/types/bridges.d.ts +38 -0
  135. package/transpiled/types/bridges.js +2 -0
  136. package/transpiled/types/bridges.js.map +1 -0
  137. package/transpiled/types/extensions.d.ts +92 -0
  138. package/transpiled/types/extensions.js +2 -0
  139. package/transpiled/types/extensions.js.map +1 -0
  140. package/transpiled/types/inbox.d.ts +22 -0
  141. package/transpiled/types/inbox.js +2 -0
  142. package/transpiled/types/inbox.js.map +1 -0
  143. package/transpiled/types/index.d.ts +14 -0
  144. package/transpiled/types/index.js +9 -0
  145. package/transpiled/types/index.js.map +1 -0
  146. package/transpiled/types/message.d.ts +16 -0
  147. package/transpiled/types/message.js +2 -0
  148. package/transpiled/types/message.js.map +1 -0
  149. package/transpiled/types/operations.d.ts +15 -0
  150. package/transpiled/types/operations.js +2 -0
  151. package/transpiled/types/operations.js.map +1 -0
  152. package/transpiled/types/outbox.d.ts +54 -0
  153. package/transpiled/types/outbox.js +2 -0
  154. package/transpiled/types/outbox.js.map +1 -0
  155. package/transpiled/types/receiver.d.ts +9 -0
  156. package/transpiled/types/receiver.js +2 -0
  157. package/transpiled/types/receiver.js.map +1 -0
  158. package/transpiled/types/request.d.ts +103 -0
  159. package/transpiled/types/request.js +2 -0
  160. package/transpiled/types/request.js.map +1 -0
  161. package/transpiled/types/state.d.ts +9 -0
  162. package/transpiled/types/state.js +2 -0
  163. package/transpiled/types/state.js.map +1 -0
  164. package/transpiled/types/storages.d.ts +146 -0
  165. package/transpiled/types/storages.js +2 -0
  166. package/transpiled/types/storages.js.map +1 -0
  167. package/transpiled/unmanaged.d.ts +5 -0
  168. package/transpiled/unmanaged.js +7 -0
  169. package/transpiled/unmanaged.js.map +1 -0
  170. package/src/assignment.js +0 -22
  171. package/src/call.js +0 -42
  172. package/src/cascade.js +0 -36
  173. package/src/component.js +0 -41
  174. package/src/composition.js +0 -25
  175. package/src/connector.js +0 -183
  176. package/src/context.js +0 -55
  177. package/src/contract/conditions.js +0 -21
  178. package/src/contract/index.js +0 -7
  179. package/src/contract/reply.js +0 -25
  180. package/src/contract/request.js +0 -67
  181. package/src/contract/schemas/error.yaml +0 -9
  182. package/src/contract/schemas/index.js +0 -7
  183. package/src/contract/schemas/query.yaml +0 -31
  184. package/src/discovery.js +0 -44
  185. package/src/emission.js +0 -23
  186. package/src/entities/changeset.js +0 -47
  187. package/src/entities/entity.js +0 -58
  188. package/src/entities/factory.js +0 -33
  189. package/src/entities/index.js +0 -5
  190. package/src/entities/set.js +0 -15
  191. package/src/event.js +0 -40
  192. package/src/exceptions.js +0 -99
  193. package/src/exposition.js +0 -27
  194. package/src/index.js +0 -47
  195. package/src/locator.js +0 -49
  196. package/src/observation.js +0 -20
  197. package/src/operation.js +0 -69
  198. package/src/query/criteria.js +0 -41
  199. package/src/query/options.js +0 -40
  200. package/src/query.js +0 -41
  201. package/src/receiver.js +0 -65
  202. package/src/reflection.js +0 -28
  203. package/src/remote.js +0 -17
  204. package/src/state.js +0 -98
  205. package/src/transition.js +0 -60
  206. package/src/transmission.js +0 -33
  207. package/test/call.fixtures.js +0 -27
  208. package/test/call.test.js +0 -46
  209. package/test/component.fixtures.js +0 -21
  210. package/test/component.test.js +0 -40
  211. package/test/connector.fixtures.js +0 -40
  212. package/test/connector.test.js +0 -176
  213. package/test/context.fixtures.js +0 -18
  214. package/test/context.test.js +0 -29
  215. package/test/contract/conditions.test.js +0 -26
  216. package/test/contract/contract.fixtures.js +0 -33
  217. package/test/contract/request.test.js +0 -112
  218. package/test/emission.fixtures.js +0 -17
  219. package/test/emission.test.js +0 -35
  220. package/test/entities/entity.fixtures.js +0 -26
  221. package/test/entities/entity.test.js +0 -76
  222. package/test/entities/factory.fixtures.js +0 -18
  223. package/test/entities/factory.test.js +0 -48
  224. package/test/entities/set.fixtures.js +0 -11
  225. package/test/entities/set.test.js +0 -12
  226. package/test/event.fixtures.js +0 -29
  227. package/test/event.test.js +0 -118
  228. package/test/locator.test.js +0 -113
  229. package/test/query.fixtures.js +0 -100
  230. package/test/query.test.js +0 -86
  231. package/test/receiver.fixtures.js +0 -23
  232. package/test/receiver.test.js +0 -95
  233. package/test/reflection.test.js +0 -30
  234. package/test/state.fixtures.js +0 -47
  235. package/test/state.test.js +0 -46
  236. package/test/transmission.fixtures.js +0 -15
  237. package/test/transmission.test.js +0 -46
  238. package/types/bindings.d.ts +0 -40
  239. package/types/bridges.ts +0 -30
  240. package/types/component.d.ts +0 -9
  241. package/types/connector.d.ts +0 -18
  242. package/types/context.d.ts +0 -21
  243. package/types/entity.d.ts +0 -46
  244. package/types/event.d.ts +0 -11
  245. package/types/exception.d.ts +0 -4
  246. package/types/extensions.d.ts +0 -29
  247. package/types/index.ts +0 -14
  248. package/types/locator.d.ts +0 -12
  249. package/types/message.d.ts +0 -3
  250. package/types/operations.d.ts +0 -2
  251. package/types/query.d.ts +0 -15
  252. package/types/receiver.d.ts +0 -12
  253. package/types/reflection.d.ts +0 -14
  254. package/types/request.d.ts +0 -23
  255. package/types/state.d.ts +0 -35
  256. package/types/storages.d.ts +0 -71
@@ -0,0 +1,193 @@
1
+ import { console } from 'openspan';
2
+ import { environment } from '@toa.io/generic';
3
+ /** Abstract connections hierarchy */
4
+ export class Connector {
5
+ #dependencies = [];
6
+ #links = [];
7
+ #connecting;
8
+ #disconnecting;
9
+ #discarded = false;
10
+ id;
11
+ connected = false;
12
+ /**
13
+ * Whether this has been taken down. What is disposed of is never connected again: a
14
+ * communication it held is sealed, an announcement it made has stopped, an algorithm it ran
15
+ * is unmounted. Whoever remembers one for the life of the process — an extension factory
16
+ * caching what it hands to components — replaces it rather than handing it out twice.
17
+ */
18
+ disposed = false;
19
+ constructor() {
20
+ this.id = this.constructor.name + '#' + Math.random().toString(36).substring(2, 8);
21
+ }
22
+ /**
23
+ * Creates a dependency and backlink with another Connector or a set of Connectors
24
+ *
25
+ * See .connect() and .disconnect()
26
+ *
27
+ */
28
+ depends(connector) {
29
+ let next;
30
+ if (connector instanceof Array) {
31
+ if (connector.length === 0)
32
+ throw new Error('Connectors array must not be empty');
33
+ if (connector.length > 1) {
34
+ next = new Connector();
35
+ for (const item of connector) {
36
+ this.#dependencies.push(item);
37
+ item.depends(next);
38
+ }
39
+ }
40
+ else
41
+ next = connector[0];
42
+ }
43
+ else
44
+ next = connector;
45
+ this.#dependencies.push(next);
46
+ next.link(this);
47
+ // See .#discard()
48
+ if (this.#disconnecting !== undefined)
49
+ next.#discard();
50
+ return next;
51
+ }
52
+ /**
53
+ * Disconnects, now and again if a connection is still to land.
54
+ *
55
+ * A dependency taken on after its dependant was disconnected — a lookup that returns
56
+ * once the teardown walk has gone by — is one nothing is left to take down, as the
57
+ * walk that would have reached it is over. One that stays connected holds open
58
+ * everything it depends on with it: a dependency reads `connected` of every dependant
59
+ * before it closes, and a dependant that is connected for good is a dependency that
60
+ * never closes.
61
+ */
62
+ #discard() {
63
+ this.#discarded = true;
64
+ // one that is up already, or on its way, is taken down here; one that is not is
65
+ // taken down by the connection when it comes, and until then there is nothing to do
66
+ if (this.#connecting !== undefined)
67
+ void this.#drop();
68
+ }
69
+ /**
70
+ * Creates a backlink to another Connector
71
+ *
72
+ * See .connect() and .disconnect()
73
+ *
74
+ */
75
+ link(connector) {
76
+ this.#links.push(connector);
77
+ }
78
+ /**
79
+ * Connects dependants then self
80
+ *
81
+ * In case of exception disconnects with current connection interruption
82
+ *
83
+ * Method is idempotent
84
+ *
85
+ */
86
+ async connect() {
87
+ if (this.#connecting)
88
+ return this.#connecting;
89
+ this.#disconnecting = undefined;
90
+ const work = async () => {
91
+ await Promise.all(this.#dependencies.map((connector) => connector.connect()));
92
+ await this.open();
93
+ };
94
+ // anonymous grouping nodes are not worth a span
95
+ const connecting = TRACE_BOOT && this.constructor.name !== 'Connector'
96
+ ? console.span({
97
+ name: `connect ${this.constructor.name}`,
98
+ // a connector that has a locator is named by it; a grouping node has none
99
+ attributes: { id: this.locator?.id ?? this.id }
100
+ }, work)
101
+ : work();
102
+ this.#connecting = connecting;
103
+ try {
104
+ await connecting;
105
+ /*
106
+ * A disconnection that did not wait for this connection emptied `#connecting` to
107
+ * say so. Reporting `connected` now would report it of a connector nothing takes
108
+ * down again — its `#disconnecting` has settled, so a later call returns at once —
109
+ * and what it depends on reads that of every dependant before it closes.
110
+ */
111
+ if (this.#connecting === connecting)
112
+ this.connected = true;
113
+ }
114
+ catch (e) {
115
+ await this.disconnect(true);
116
+ throw e;
117
+ }
118
+ // a connection asked for before this one was discarded, landing after. See .#discard()
119
+ if (this.#discarded)
120
+ await this.#drop();
121
+ }
122
+ /** Disconnects a discarded connector, saying so rather than throwing at whoever is not waiting. */
123
+ async #drop() {
124
+ this.#discarded = false;
125
+ try {
126
+ await this.disconnect();
127
+ }
128
+ catch (error) {
129
+ console.error('Discarded connector failed to disconnect', { id: this.id, error });
130
+ }
131
+ }
132
+ /**
133
+ * Disconnects self then dependants
134
+ *
135
+ * Does nothing if there are connected linked Connectors
136
+ *
137
+ * Method is idempotent
138
+ *
139
+ */
140
+ async disconnect(interrupt) {
141
+ // a connector that has not finished connecting has nothing to close, and
142
+ // awaiting a connection that may never settle outlives any grace period
143
+ const pending = interrupt === true || this.connected === false;
144
+ if (!pending)
145
+ await this.#connecting;
146
+ if (this.#disconnecting)
147
+ return this.#disconnecting;
148
+ const linked = this.#links.reduce((acc, parent) => acc || parent.connected, false);
149
+ if (linked && interrupt !== true)
150
+ return;
151
+ this.#disconnecting = (async () => {
152
+ const start = +new Date();
153
+ const interval = setInterval(() => {
154
+ const delay = +new Date() - start;
155
+ if (delay > DELAY)
156
+ console.warn(`Connector ${this.id} still disconnecting (${delay})`);
157
+ }, DELAY);
158
+ if (!pending)
159
+ await this.close();
160
+ // said once the closing is done rather than when it starts: a dependant that is
161
+ // still closing is still using what it depends on, and the check above reads this
162
+ // of every dependant. Saying it early lets the first to start tear down a shared
163
+ // dependency under the others.
164
+ this.connected = false;
165
+ this.#connecting = undefined;
166
+ clearInterval(interval);
167
+ await Promise.all(this.#dependencies.map((connector) => connector.disconnect()));
168
+ await this.dispose();
169
+ this.disposed = true;
170
+ })();
171
+ await this.#disconnecting;
172
+ }
173
+ async reconnect() {
174
+ await this.disconnect();
175
+ await this.connect();
176
+ }
177
+ debug(node = {}) {
178
+ node[this.id] = { connected: this.connected };
179
+ if (this.#dependencies.length > 0)
180
+ for (const connector of this.#dependencies)
181
+ connector.debug?.(node[this.id]);
182
+ return node;
183
+ }
184
+ /** Called on connection */
185
+ open() { }
186
+ /** Called on disconnection */
187
+ close() { }
188
+ /** Called after self and dependants disconnection is complete */
189
+ dispose() { }
190
+ }
191
+ const DELAY = 5000;
192
+ const TRACE_BOOT = environment.get('TOA_BOOT_TRACE') === '1';
193
+ //# sourceMappingURL=connector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connector.js","sourceRoot":"","sources":["../source/connector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { Connector } from './connector.js';
2
+ import type { Locator } from './locator.js';
3
+ import type { Component } from './component.js';
4
+ import type { Remote } from './remote.js';
5
+ import type { Aspect } from './types/extensions.js';
6
+ import type { Options, Request } from './types/request.js';
7
+ type Discover = (namespace: string, name: string) => Promise<Remote>;
8
+ export declare class Context extends Connector {
9
+ #private;
10
+ readonly env: string | undefined;
11
+ readonly name: string | undefined;
12
+ /**
13
+ * The rank of the region this deployment is, which is what its writes are stamped with. A
14
+ * deployment that is no region at all reads as zero, which is what its records carry.
15
+ */
16
+ readonly region: number;
17
+ readonly aspects: Aspect[];
18
+ readonly locator: Locator;
19
+ /** The name this process answers addressed calls under. */
20
+ readonly instance: string;
21
+ constructor(local: Component, discover: Discover, aspects?: Aspect[]);
22
+ apply(endpoint: string, request: Request, options?: Options): Promise<any>;
23
+ call(namespace: string, name: string, endpoint: string, request: Request, options?: Options): Promise<any>;
24
+ }
25
+ export {};
@@ -0,0 +1,55 @@
1
+ import { Connector } from './connector.js';
2
+ import { waiting } from './abandon.js';
3
+ import { instance } from './instance.js';
4
+ import { environment } from '@toa.io/generic';
5
+ export class Context extends Connector {
6
+ env;
7
+ name;
8
+ /**
9
+ * The rank of the region this deployment is, which is what its writes are stamped with. A
10
+ * deployment that is no region at all reads as zero, which is what its records carry.
11
+ */
12
+ region;
13
+ aspects;
14
+ locator;
15
+ /** The name this process answers addressed calls under. */
16
+ instance;
17
+ #local;
18
+ #discover;
19
+ #remotes = {};
20
+ constructor(local, discover, aspects = []) {
21
+ super();
22
+ this.env = environment.get('TOA_ENV');
23
+ this.name = environment.get('TOA_CONTEXT');
24
+ this.region = Number(environment.get('TOA_REGION') ?? 0);
25
+ this.aspects = aspects;
26
+ this.locator = local?.locator;
27
+ this.instance = instance();
28
+ this.#local = local;
29
+ this.#discover = discover;
30
+ this.depends(local);
31
+ if (aspects.length > 0)
32
+ this.depends(aspects);
33
+ }
34
+ async apply(endpoint, request, options) {
35
+ return this.#local.invoke(endpoint, request, options);
36
+ }
37
+ // eslint-disable-next-line max-params
38
+ async call(namespace, name, endpoint, request, options) {
39
+ // the lookup is waited for as the call is: a caller that stops waiting is answered at once, and
40
+ // the lookup finishes for the next call to use
41
+ const remote = await waiting(this.#remote(namespace, name), options?.signal, `${namespace}.${name}.${endpoint}`);
42
+ return remote.invoke(endpoint, request, options);
43
+ }
44
+ async #remote(namespace, name) {
45
+ const key = namespace + '.' + name;
46
+ this.#remotes[key] ??= this.#connect(namespace, name);
47
+ return this.#remotes[key];
48
+ }
49
+ async #connect(namespace, name) {
50
+ const remote = await this.#discover(namespace, name);
51
+ this.depends(remote);
52
+ return remote;
53
+ }
54
+ }
55
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../source/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAS7C,MAAM,OAAO,OAAQ,SAAQ,SAAS;IACpB,GAAG,CAAoB;IACvB,IAAI,CAAoB;IAExC;;;OAGG;IACa,MAAM,CAAQ;IAEd,OAAO,CAAU;IACjB,OAAO,CAAS;IAEhC,2DAA2D;IAC3C,QAAQ,CAAQ;IAEvB,MAAM,CAAW;IACjB,SAAS,CAAU;IACnB,QAAQ,GAAoC,EAAE,CAAA;IAEvD,YAAmB,KAAgB,EAAE,QAAkB,EAAE,OAAO,GAAa,EAAE;QAC7E,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACrC,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;QAC1C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;QACxD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,EAAE,OAAO,CAAA;QAC7B,IAAI,CAAC,QAAQ,GAAG,QAAQ,EAAE,CAAA;QAE1B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;QACnB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAA;QAEzB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAEnB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/C,CAAC;IAEM,KAAK,CAAC,KAAK,CAAC,QAAgB,EAAE,OAAgB,EAAE,OAAiB;QACtE,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IACvD,CAAC;IAED,sCAAsC;IAC/B,KAAK,CAAC,IAAI,CACf,SAAiB,EACjB,IAAY,EACZ,QAAgB,EAChB,OAAgB,EAChB,OAAiB;QAEjB,gGAAgG;QAChG,+CAA+C;QAC/C,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,EAC7B,OAAO,EAAE,MAAM,EACf,GAAG,SAAS,IAAI,IAAI,IAAI,QAAQ,EAAE,CACnC,CAAA;QAED,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IAClD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,IAAY;QAC3C,MAAM,GAAG,GAAG,SAAS,GAAG,GAAG,GAAG,IAAI,CAAA;QAElC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QAErD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,SAAiB,EAAE,IAAY;QAC5C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QAEpD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAEpB,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import type { Schema, SchemaError } from '@toa.io/schemas';
2
+ import type { Exception } from '../exceptions.js';
3
+ /** What a contract throws with, stated by the subclass. */
4
+ export type Refusal = new (error: SchemaError, cause?: unknown) => Exception;
5
+ export declare class Contract {
6
+ readonly schema: Schema;
7
+ static Exception: Refusal;
8
+ constructor(schema: Schema);
9
+ fit(value: unknown): void;
10
+ }
@@ -0,0 +1,14 @@
1
+ import { SystemException } from '../exceptions.js';
2
+ export class Contract {
3
+ schema;
4
+ static Exception = SystemException;
5
+ constructor(schema) {
6
+ this.schema = schema;
7
+ }
8
+ fit(value) {
9
+ const error = this.schema.fit(value);
10
+ if (error !== null)
11
+ throw new this.constructor.Exception(error, value);
12
+ }
13
+ }
14
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../source/contract/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAOlD,MAAM,OAAO,QAAQ;IACH,MAAM,CAAQ;IAEvB,MAAM,CAAC,SAAS,GAAY,eAAqC,CAAA;IAExE,YAAmB,MAAc;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAEM,GAAG,CAAC,KAAc;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAEpC,IAAI,KAAK,KAAK,IAAI;YAChB,MAAM,IAAK,IAAI,CAAC,WAA+B,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IAC3E,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export { Request } from './request.js';
2
+ export { Reply } from './reply.js';
@@ -0,0 +1,3 @@
1
+ export { Request } from './request.js';
2
+ export { Reply } from './reply.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/contract/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { Contract } from './contract.js';
2
+ import type { Refusal } from './contract.js';
3
+ import type { JSONSchema } from './schemas.js';
4
+ export declare class Reply extends Contract {
5
+ static Exception: Refusal;
6
+ static schema(output?: JSONSchema, errors?: Array<string | number>): JSONSchema;
7
+ }
@@ -0,0 +1,48 @@
1
+ import { Contract } from './contract.js';
2
+ import { ResponseContractException } from '../exceptions.js';
3
+ export class Reply extends Contract {
4
+ static Exception = ResponseContractException;
5
+ static schema(output, errors) {
6
+ const schema = {
7
+ type: 'object',
8
+ properties: {},
9
+ additionalProperties: false
10
+ };
11
+ if (output !== undefined) {
12
+ /*
13
+ * A reply carries more than the operation declares — `VERSION` and the rest of the
14
+ * record's own fields — so what it is validated against is the declaration relaxed.
15
+ * On a copy: the declaration itself is what a component publishes when asked to
16
+ * explain, and relaxing that would publish a contract nobody wrote.
17
+ */
18
+ output = structuredClone(output);
19
+ if (output.type === 'object')
20
+ output.additionalProperties = true;
21
+ else if (output.type === 'array' && output.items?.type === 'object')
22
+ output.items.additionalProperties = true;
23
+ schema.properties.output = output;
24
+ }
25
+ /*
26
+ * An error a caller is meant to handle is one the operation states. Where none are
27
+ * stated, an error is not a reply this operation makes — it is a mistake, and the
28
+ * contract says so rather than passing an undeclared code on to whoever called.
29
+ */
30
+ schema.properties.error =
31
+ errors === undefined
32
+ ? false
33
+ : {
34
+ type: 'object',
35
+ properties: {
36
+ code: {
37
+ enum: errors
38
+ },
39
+ message: {
40
+ type: 'string'
41
+ }
42
+ },
43
+ required: ['code']
44
+ };
45
+ return schema;
46
+ }
47
+ }
48
+ //# sourceMappingURL=reply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply.js","sourceRoot":"","sources":["../../source/contract/reply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAA;AAI5D,MAAM,OAAO,KAAM,SAAQ,QAAQ;IAC1B,MAAM,CAAU,SAAS,GAC9B,yBAA+C,CAAA;IAE1C,MAAM,CAAC,MAAM,CAAC,MAAmB,EAAE,MAA+B;QACvE,MAAM,MAAM,GAAe;YACzB,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE;YACd,oBAAoB,EAAE,KAAK;SAC5B,CAAA;QAED,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB;;;;;eAKG;YACH,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAA;YAEhC,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,CAAC,oBAAoB,GAAG,IAAI,CAAA;iBAC3D,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,IAAI,KAAK,QAAQ;gBACjE,MAAM,CAAC,KAAK,CAAC,oBAAoB,GAAG,IAAI,CAAA;YAE1C,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,MAAM,CAAA;QACnC,CAAC;QAED;;;;WAIG;QACH,MAAM,CAAC,UAAU,CAAC,KAAK;YACrB,MAAM,KAAK,SAAS;gBAClB,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC;oBACE,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,IAAI,EAAE;4BACJ,IAAI,EAAE,MAAM;yBACb;wBACD,OAAO,EAAE;4BACP,IAAI,EAAE,QAAQ;yBACf;qBACF;oBACD,QAAQ,EAAE,CAAC,MAAM,CAAC;iBACnB,CAAA;QAEP,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
@@ -0,0 +1,39 @@
1
+ import { Contract } from './contract.js';
2
+ import type { Schema } from '@toa.io/schemas';
3
+ import type { Refusal } from './contract.js';
4
+ import type { JSONSchema } from './schemas.js';
5
+ /** What an operation states about itself, and answers when asked to explain. */
6
+ export interface Explanation {
7
+ description?: string;
8
+ /**
9
+ * Whether the same call arriving twice changes state once. Said, because a caller cannot tell
10
+ * it from an answer that says nothing, and what it changes is whether a retry is safe to make.
11
+ */
12
+ once?: boolean;
13
+ /**
14
+ * Whether a call to it names the process it goes to. Said, because the caller is the one who
15
+ * has to name one, and a call that names none is refused.
16
+ */
17
+ stateful?: boolean;
18
+ input?: JSONSchema | null;
19
+ output?: JSONSchema | null;
20
+ errors?: Array<string | number>;
21
+ }
22
+ export interface Definition extends Explanation {
23
+ type?: string;
24
+ scope?: string;
25
+ query?: boolean;
26
+ }
27
+ /** What the operation works on, as the manifest declares it. */
28
+ export interface Entity {
29
+ properties: Record<string, JSONSchema>;
30
+ required?: string[];
31
+ }
32
+ export declare class Request extends Contract {
33
+ readonly discovery: Explanation;
34
+ static Exception: Refusal;
35
+ constructor(schema: Schema, definition: Definition, entity?: Entity);
36
+ static schema(definition: Definition, entity?: {
37
+ properties: Record<string, JSONSchema>;
38
+ }): JSONSchema;
39
+ }
@@ -0,0 +1,111 @@
1
+ import * as schemas from './schemas.js';
2
+ import { RequestContractException } from '../exceptions.js';
3
+ import { Contract } from './contract.js';
4
+ export class Request extends Contract {
5
+ discovery = {};
6
+ static Exception = RequestContractException;
7
+ constructor(schema, definition, entity) {
8
+ super(schema);
9
+ for (const key of ['description', 'once', 'stateful', 'input', 'output', 'errors'])
10
+ if (definition[key] !== undefined)
11
+ this.discovery[key] = definition[key];
12
+ /*
13
+ * An operation that states no output states an empty schema, which every reply fits —
14
+ * and which says nothing to whoever reads it. What its type answers does, so that is
15
+ * said here instead. Here and not in the definition, because the definition is what a
16
+ * reply is held to: a projection is a lawful answer, and describing one is not the same
17
+ * as requiring it.
18
+ */
19
+ if (empty(this.discovery.output)) {
20
+ const answered = answers(definition, entity);
21
+ if (answered !== undefined)
22
+ this.discovery.output = answered;
23
+ }
24
+ }
25
+ static schema(definition, entity) {
26
+ // `source` is not among these: the framework stamps it and whoever reads it takes the keys
27
+ // it knows, so holding it to a schema would only fail calls from a peer that stamps one more
28
+ const schema = {
29
+ type: 'object',
30
+ properties: {
31
+ /*
32
+ * Listed, and not required. `additionalProperties` already admits it, and a callee skips
33
+ * this contract altogether for an `authentic` request — which every request from a `Call`
34
+ * is — so requiring it would refuse nothing on the side where a missing identity matters,
35
+ * and would refuse every request built by hand on the side where it never is. An
36
+ * operation that declares `once` raises on a request without one instead.
37
+ */
38
+ id: { type: 'string' },
39
+ authentic: { type: 'boolean' },
40
+ task: { type: 'boolean' }
41
+ },
42
+ additionalProperties: true
43
+ };
44
+ const required = [];
45
+ if (definition.input !== undefined) {
46
+ schema.properties.input = definition.input;
47
+ required.push('input');
48
+ }
49
+ else
50
+ schema.properties.input = { type: 'null' };
51
+ if (entity === undefined)
52
+ definition.query = false;
53
+ if (definition.query === true)
54
+ required.push('query');
55
+ if (definition.query === false)
56
+ schema.properties.query = { type: 'null' };
57
+ if (definition.query !== false) {
58
+ const query = structuredClone(schemas.query);
59
+ query.properties.id = entity?.properties.id;
60
+ if (definition.type === 'observation')
61
+ delete query.properties.version;
62
+ else
63
+ delete query.properties.projection;
64
+ if (definition.type !== 'observation' || definition.scope !== 'objects') {
65
+ delete query.properties.omit;
66
+ delete query.properties.limit;
67
+ }
68
+ else if (query.required === undefined)
69
+ query.required = ['limit'];
70
+ else
71
+ query.required.push('limit');
72
+ schema.properties.query = query;
73
+ }
74
+ if (required.length > 0)
75
+ schema.required = required;
76
+ return schema;
77
+ }
78
+ }
79
+ /**
80
+ * What an operation of this type answers, where it did not say.
81
+ *
82
+ * A transition, an observation and an assignment work on the Entity Object, so that is what
83
+ * they answer — a set of them where the scope is a set. A computation neither uses the scope
84
+ * nor produces one, and an effect answers whatever it computed, so neither is guessed at.
85
+ * A stream is not a value with a schema, and is not one either.
86
+ *
87
+ * What the entity requires is said as well. It is a description and nothing is held to it —
88
+ * an operation answering a projection says so by declaring its own output — and a shape
89
+ * whose every property reads as optional says less than it knows.
90
+ */
91
+ function answers(definition, entity) {
92
+ if (entity === undefined || !ENTITY.has(definition.type))
93
+ return undefined;
94
+ const object = {
95
+ type: 'object',
96
+ properties: entity.properties,
97
+ ...(entity.required === undefined ? {} : { required: entity.required })
98
+ };
99
+ if (definition.scope === 'objects')
100
+ return { type: 'array', items: object };
101
+ return definition.scope === 'object' || definition.scope === 'changeset'
102
+ ? object
103
+ : undefined;
104
+ }
105
+ /** The types whose subject is the Entity Object; see `documentation/design.md`. */
106
+ const ENTITY = new Set(['transition', 'observation', 'assignment']);
107
+ /** A schema that states nothing, which is what an operation saying nothing normalizes to. */
108
+ function empty(schema) {
109
+ return schema === undefined || schema === null || Object.keys(schema).length === 0;
110
+ }
111
+ //# sourceMappingURL=request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../source/contract/request.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** A JSON Schema, loose because it is handed to a validator and edited by the contracts. */
2
+ export type JSONSchema = Record<string, any>;
3
+ export declare const query: JSONSchema;
4
+ export declare const error: JSONSchema;
@@ -0,0 +1,36 @@
1
+ export const query = {
2
+ type: 'object',
3
+ properties: {
4
+ id: { type: 'string' },
5
+ ids: { type: 'array', uniqueItems: true, minItems: 1, items: { type: 'string' } },
6
+ version: { type: 'integer', minimum: 0 },
7
+ criteria: { type: 'string' },
8
+ search: { type: 'string' },
9
+ sample: { type: 'number' },
10
+ omit: { type: 'integer', minimum: 0 },
11
+ limit: { type: 'integer', minimum: 0 },
12
+ sort: {
13
+ type: 'array',
14
+ uniqueItems: true,
15
+ minItems: 1,
16
+ items: { type: 'string', pattern: '^\\w{1,32}(?::(?:asc|desc))?$' }
17
+ },
18
+ projection: {
19
+ type: 'array',
20
+ uniqueItems: true,
21
+ minItems: 1,
22
+ items: { type: 'string', not: { const: 'id' } }
23
+ },
24
+ deleted: { type: 'boolean' }
25
+ },
26
+ additionalProperties: false
27
+ };
28
+ export const error = {
29
+ type: 'object',
30
+ properties: {
31
+ code: { anyOf: [{ type: 'integer' }, { type: 'string' }] },
32
+ message: { type: 'string' }
33
+ },
34
+ required: ['code']
35
+ };
36
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../source/contract/schemas.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,KAAK,GAAe;IAC/B,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACtB,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QACjF,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACxC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC5B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC1B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACrC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,IAAI,EAAE;YACJ,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,+BAA+B,EAAE;SACpE;QACD,UAAU,EAAE;YACV,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;SAChD;QACD,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;KAC7B;IACD,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAe;IAC/B,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE;QAC1D,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC5B;IACD,QAAQ,EAAE,CAAC,MAAM,CAAC;CACnB,CAAA"}
@@ -0,0 +1,19 @@
1
+ import { Connector } from './connector.js';
2
+ import type { Locator } from './locator.js';
3
+ interface Lookup extends Connector {
4
+ invoke: () => Promise<any>;
5
+ }
6
+ export declare class Discovery extends Connector {
7
+ #private;
8
+ constructor(lookup: (locator: Locator) => Promise<Lookup>);
9
+ protected open(): Promise<void>;
10
+ /**
11
+ * A lookup is unbounded, so one in flight when this goes away never settles and would go on
12
+ * saying it is waiting for the life of the process. Which nothing noticed while a
13
+ * disconnected discovery meant a process on its way out — a halt takes one down and builds
14
+ * another, and every cycle would leave a voice behind.
15
+ */
16
+ protected close(): Promise<void>;
17
+ lookup(locator: Locator): Promise<any>;
18
+ }
19
+ export {};