@toa.io/core 1.0.0-alpha.283 → 1.0.0-alpha.286

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 (290) hide show
  1. package/package.json +19 -7
  2. package/source/assignment.ts +27 -0
  3. package/{src/call.js → source/call.ts} +16 -21
  4. package/{src/cascade.js → source/cascade.ts} +6 -8
  5. package/{src/component.js → source/component.ts} +27 -25
  6. package/{src/composition.js → source/composition.ts} +9 -3
  7. package/{src/connector.js → source/connector.ts} +36 -55
  8. package/source/context.ts +67 -0
  9. package/source/contract/contract.ts +23 -0
  10. package/{src/contract/reply.js → source/contract/reply.ts} +26 -19
  11. package/source/contract/request.ts +85 -0
  12. package/source/contract/schemas.ts +39 -0
  13. package/{src/discovery.js → source/discovery.ts} +15 -8
  14. package/source/effect.ts +14 -0
  15. package/{src/emission.js → source/emission.ts} +5 -3
  16. package/source/entities/changeset.ts +37 -0
  17. package/source/entities/entity.ts +137 -0
  18. package/source/entities/factory.ts +52 -0
  19. package/source/entities/index.ts +4 -0
  20. package/{src/entities/newid.js → source/entities/newid.ts} +1 -1
  21. package/{src/entities/set.js → source/entities/set.ts} +8 -5
  22. package/source/event.ts +57 -0
  23. package/{src/exceptions.js → source/exceptions.ts} +52 -33
  24. package/source/exposition.ts +33 -0
  25. package/source/guard.ts +16 -0
  26. package/{src/index.js → source/index.ts} +8 -0
  27. package/{src/locator.js → source/locator.ts} +17 -30
  28. package/source/observation.ts +16 -0
  29. package/source/operation.ts +138 -0
  30. package/{src/outbox/outbox.js → source/outbox/outbox.ts} +95 -51
  31. package/source/query/criteria.ts +90 -0
  32. package/source/query/options.ts +35 -0
  33. package/{src/query.js → source/query.ts} +14 -17
  34. package/source/receiver.ts +120 -0
  35. package/source/reflection.ts +20 -0
  36. package/source/remote.ts +20 -0
  37. package/source/state.ts +179 -0
  38. package/source/transition.ts +79 -0
  39. package/{src/transmission.js → source/transmission.ts} +8 -8
  40. package/source/types/atomicity.ts +63 -0
  41. package/source/types/bindings.ts +59 -0
  42. package/source/types/bridges.ts +54 -0
  43. package/source/types/extensions.ts +89 -0
  44. package/{types → source/types}/index.ts +9 -16
  45. package/{types/message.d.ts → source/types/message.ts} +2 -1
  46. package/source/types/operations.ts +31 -0
  47. package/source/types/outbox.ts +35 -0
  48. package/source/types/receiver.ts +10 -0
  49. package/{types/request.d.ts → source/types/request.ts} +8 -9
  50. package/source/types/state.ts +9 -0
  51. package/source/types/storages.ts +129 -0
  52. package/source/unmanaged.ts +8 -0
  53. package/test/call.fixtures.js +3 -1
  54. package/test/call.test.js +28 -7
  55. package/test/component.test.js +10 -5
  56. package/test/connector.fixtures.js +7 -7
  57. package/test/connector.test.js +15 -2
  58. package/test/context.fixtures.js +1 -1
  59. package/test/context.test.js +4 -4
  60. package/test/contract/conditions.test.js +6 -2
  61. package/test/contract/contract.fixtures.js +3 -4
  62. package/test/contract/request.test.js +68 -34
  63. package/test/discovery.test.js +10 -3
  64. package/test/emission.test.js +16 -8
  65. package/test/entities/entity.fixtures.js +5 -6
  66. package/test/entities/entity.test.js +54 -20
  67. package/test/entities/factory.fixtures.js +11 -10
  68. package/test/entities/factory.test.js +47 -10
  69. package/test/entities/set.test.js +1 -1
  70. package/test/event.test.js +29 -11
  71. package/test/locator.test.js +10 -4
  72. package/test/outbox.test.js +95 -14
  73. package/test/query.test.js +76 -7
  74. package/test/receiver.fixtures.js +2 -2
  75. package/test/receiver.test.js +53 -27
  76. package/test/reflection.test.js +3 -3
  77. package/test/state.fixtures.js +10 -3
  78. package/test/state.test.js +77 -14
  79. package/test/transmission.test.js +25 -12
  80. package/transpiled/assignment.d.ts +6 -0
  81. package/transpiled/assignment.js +20 -0
  82. package/transpiled/assignment.js.map +1 -0
  83. package/transpiled/call.d.ts +10 -0
  84. package/transpiled/call.js +52 -0
  85. package/transpiled/call.js.map +1 -0
  86. package/transpiled/cascade.d.ts +7 -0
  87. package/transpiled/cascade.js +28 -0
  88. package/transpiled/cascade.js.map +1 -0
  89. package/transpiled/component.d.ts +15 -0
  90. package/transpiled/component.js +61 -0
  91. package/transpiled/component.js.map +1 -0
  92. package/transpiled/composition.d.ts +6 -0
  93. package/transpiled/composition.js +23 -0
  94. package/transpiled/composition.js.map +1 -0
  95. package/transpiled/connector.d.ts +47 -0
  96. package/transpiled/connector.js +143 -0
  97. package/transpiled/connector.js.map +1 -0
  98. package/transpiled/context.d.ts +18 -0
  99. package/transpiled/context.js +41 -0
  100. package/transpiled/context.js.map +1 -0
  101. package/transpiled/contract/contract.d.ts +10 -0
  102. package/transpiled/contract/contract.js +14 -0
  103. package/transpiled/contract/contract.js.map +1 -0
  104. package/transpiled/contract/index.d.ts +2 -0
  105. package/transpiled/contract/index.js +3 -0
  106. package/transpiled/contract/index.js.map +1 -0
  107. package/transpiled/contract/reply.d.ts +7 -0
  108. package/transpiled/contract/reply.js +48 -0
  109. package/transpiled/contract/reply.js.map +1 -0
  110. package/transpiled/contract/request.d.ts +24 -0
  111. package/transpiled/contract/request.js +59 -0
  112. package/transpiled/contract/request.js.map +1 -0
  113. package/transpiled/contract/schemas.d.ts +4 -0
  114. package/transpiled/contract/schemas.js +36 -0
  115. package/transpiled/contract/schemas.js.map +1 -0
  116. package/transpiled/discovery.d.ts +12 -0
  117. package/transpiled/discovery.js +34 -0
  118. package/transpiled/discovery.js.map +1 -0
  119. package/transpiled/effect.d.ts +5 -0
  120. package/transpiled/effect.js +11 -0
  121. package/transpiled/effect.js.map +1 -0
  122. package/transpiled/emission.d.ts +8 -0
  123. package/transpiled/emission.js +14 -0
  124. package/transpiled/emission.js.map +1 -0
  125. package/transpiled/entities/changeset.d.ts +10 -0
  126. package/transpiled/entities/changeset.js +27 -0
  127. package/transpiled/entities/changeset.js.map +1 -0
  128. package/transpiled/entities/entity.d.ts +19 -0
  129. package/transpiled/entities/entity.js +109 -0
  130. package/transpiled/entities/entity.js.map +1 -0
  131. package/transpiled/entities/factory.d.ts +22 -0
  132. package/transpiled/entities/factory.js +34 -0
  133. package/transpiled/entities/factory.js.map +1 -0
  134. package/transpiled/entities/index.d.ts +4 -0
  135. package/transpiled/entities/index.js +5 -0
  136. package/transpiled/entities/index.js.map +1 -0
  137. package/transpiled/entities/newid.d.ts +1 -0
  138. package/transpiled/entities/newid.js +7 -0
  139. package/transpiled/entities/newid.js.map +1 -0
  140. package/transpiled/entities/set.d.ts +10 -0
  141. package/transpiled/entities/set.js +19 -0
  142. package/transpiled/entities/set.js.map +1 -0
  143. package/transpiled/event.d.ts +14 -0
  144. package/transpiled/event.js +38 -0
  145. package/transpiled/event.js.map +1 -0
  146. package/transpiled/exceptions.d.ts +61 -0
  147. package/transpiled/exceptions.js +93 -0
  148. package/transpiled/exceptions.js.map +1 -0
  149. package/transpiled/exposition.d.ts +18 -0
  150. package/transpiled/exposition.js +18 -0
  151. package/transpiled/exposition.js.map +1 -0
  152. package/transpiled/guard.d.ts +7 -0
  153. package/transpiled/guard.js +12 -0
  154. package/transpiled/guard.js.map +1 -0
  155. package/transpiled/index.d.ts +35 -0
  156. package/transpiled/index.js +29 -0
  157. package/transpiled/index.js.map +1 -0
  158. package/transpiled/locator.d.ts +12 -0
  159. package/transpiled/locator.js +32 -0
  160. package/transpiled/locator.js.map +1 -0
  161. package/transpiled/observation.d.ts +5 -0
  162. package/transpiled/observation.js +12 -0
  163. package/transpiled/observation.js.map +1 -0
  164. package/transpiled/operation.d.ts +49 -0
  165. package/transpiled/operation.js +77 -0
  166. package/transpiled/operation.js.map +1 -0
  167. package/transpiled/outbox/index.d.ts +1 -0
  168. package/transpiled/outbox/index.js +2 -0
  169. package/transpiled/outbox/index.js.map +1 -0
  170. package/transpiled/outbox/outbox.d.ts +46 -0
  171. package/transpiled/outbox/outbox.js +267 -0
  172. package/transpiled/outbox/outbox.js.map +1 -0
  173. package/transpiled/query/criteria.d.ts +6 -0
  174. package/transpiled/query/criteria.js +74 -0
  175. package/transpiled/query/criteria.js.map +1 -0
  176. package/transpiled/query/options.d.ts +3 -0
  177. package/transpiled/query/options.js +27 -0
  178. package/transpiled/query/options.js.map +1 -0
  179. package/transpiled/query.d.ts +9 -0
  180. package/transpiled/query.js +57 -0
  181. package/transpiled/query.js.map +1 -0
  182. package/transpiled/receiver.d.ts +20 -0
  183. package/transpiled/receiver.js +92 -0
  184. package/transpiled/receiver.js.map +1 -0
  185. package/transpiled/reflection.d.ts +9 -0
  186. package/transpiled/reflection.js +13 -0
  187. package/transpiled/reflection.js.map +1 -0
  188. package/transpiled/remote.d.ts +10 -0
  189. package/transpiled/remote.js +12 -0
  190. package/transpiled/remote.js.map +1 -0
  191. package/transpiled/state.d.ts +33 -0
  192. package/transpiled/state.js +126 -0
  193. package/transpiled/state.js.map +1 -0
  194. package/transpiled/transition.d.ts +14 -0
  195. package/transpiled/transition.js +51 -0
  196. package/transpiled/transition.js.map +1 -0
  197. package/transpiled/transmission.d.ts +8 -0
  198. package/transpiled/transmission.js +30 -0
  199. package/transpiled/transmission.js.map +1 -0
  200. package/transpiled/types/atomicity.d.ts +56 -0
  201. package/transpiled/types/atomicity.js +2 -0
  202. package/transpiled/types/atomicity.js.map +1 -0
  203. package/transpiled/types/bindings.d.ts +42 -0
  204. package/transpiled/types/bindings.js +2 -0
  205. package/transpiled/types/bindings.js.map +1 -0
  206. package/transpiled/types/bridges.d.ts +38 -0
  207. package/transpiled/types/bridges.js +2 -0
  208. package/transpiled/types/bridges.js.map +1 -0
  209. package/transpiled/types/extensions.d.ts +62 -0
  210. package/transpiled/types/extensions.js +2 -0
  211. package/transpiled/types/extensions.js.map +1 -0
  212. package/transpiled/types/index.d.ts +13 -0
  213. package/transpiled/types/index.js +8 -0
  214. package/transpiled/types/index.js.map +1 -0
  215. package/transpiled/types/message.d.ts +5 -0
  216. package/transpiled/types/message.js +2 -0
  217. package/transpiled/types/message.js.map +1 -0
  218. package/transpiled/types/operations.d.ts +15 -0
  219. package/transpiled/types/operations.js +2 -0
  220. package/transpiled/types/operations.js.map +1 -0
  221. package/transpiled/types/outbox.d.ts +28 -0
  222. package/transpiled/types/outbox.js +2 -0
  223. package/transpiled/types/outbox.js.map +1 -0
  224. package/transpiled/types/receiver.d.ts +9 -0
  225. package/transpiled/types/receiver.js +2 -0
  226. package/transpiled/types/receiver.js.map +1 -0
  227. package/transpiled/types/request.d.ts +55 -0
  228. package/transpiled/types/request.js +2 -0
  229. package/transpiled/types/request.js.map +1 -0
  230. package/transpiled/types/state.d.ts +9 -0
  231. package/transpiled/types/state.js +2 -0
  232. package/transpiled/types/state.js.map +1 -0
  233. package/transpiled/types/storages.d.ts +106 -0
  234. package/transpiled/types/storages.js +2 -0
  235. package/transpiled/types/storages.js.map +1 -0
  236. package/transpiled/unmanaged.d.ts +5 -0
  237. package/transpiled/unmanaged.js +7 -0
  238. package/transpiled/unmanaged.js.map +1 -0
  239. package/tsconfig.json +10 -0
  240. package/tsconfig.tsbuildinfo +1 -0
  241. package/CHANGELOG.md +0 -180
  242. package/src/assignment.js +0 -28
  243. package/src/context.js +0 -57
  244. package/src/contract/contract.js +0 -18
  245. package/src/contract/request.js +0 -77
  246. package/src/contract/schemas/error.yaml +0 -9
  247. package/src/contract/schemas/index.js +0 -11
  248. package/src/contract/schemas/query.yaml +0 -43
  249. package/src/contract/schemas/source.yaml +0 -23
  250. package/src/effect.js +0 -15
  251. package/src/entities/changeset.js +0 -36
  252. package/src/entities/entity.js +0 -119
  253. package/src/entities/factory.js +0 -40
  254. package/src/entities/index.js +0 -1
  255. package/src/event.js +0 -54
  256. package/src/exposition.js +0 -24
  257. package/src/guard.js +0 -13
  258. package/src/observation.js +0 -8
  259. package/src/operation.js +0 -95
  260. package/src/query/criteria.js +0 -37
  261. package/src/query/options.js +0 -37
  262. package/src/receiver.js +0 -123
  263. package/src/reflection.js +0 -24
  264. package/src/remote.js +0 -14
  265. package/src/state.js +0 -138
  266. package/src/transition.js +0 -61
  267. package/src/unmanaged.js +0 -7
  268. package/types/atomicity.d.ts +0 -58
  269. package/types/bindings.d.ts +0 -42
  270. package/types/bridges.ts +0 -33
  271. package/types/call.d.ts +0 -13
  272. package/types/component.d.ts +0 -12
  273. package/types/connector.d.ts +0 -18
  274. package/types/context.d.ts +0 -24
  275. package/types/entity.d.ts +0 -46
  276. package/types/event.d.ts +0 -11
  277. package/types/exception.d.ts +0 -4
  278. package/types/extensions.d.ts +0 -73
  279. package/types/guard.d.ts +0 -5
  280. package/types/locator.d.ts +0 -13
  281. package/types/operations.d.ts +0 -8
  282. package/types/outbox.d.ts +0 -53
  283. package/types/query.d.ts +0 -17
  284. package/types/receiver.d.ts +0 -12
  285. package/types/reflection.d.ts +0 -14
  286. package/types/remote.d.ts +0 -18
  287. package/types/state.d.ts +0 -38
  288. package/types/storages.d.ts +0 -96
  289. /package/{src/contract/index.js → source/contract/index.ts} +0 -0
  290. /package/{src/outbox/index.js → source/outbox/index.ts} +0 -0
@@ -0,0 +1,143 @@
1
+ import { console } from 'openspan';
2
+ /** Abstract connections hierarchy */
3
+ export class Connector {
4
+ #dependencies = [];
5
+ #links = [];
6
+ #connecting;
7
+ #disconnecting;
8
+ id;
9
+ connected = false;
10
+ constructor() {
11
+ this.id = this.constructor.name + '#' + Math.random().toString(36).substring(2, 8);
12
+ }
13
+ /**
14
+ * Creates a dependency and backlink with another Connector or a set of Connectors
15
+ *
16
+ * See .connect() and .disconnect()
17
+ *
18
+ */
19
+ depends(connector) {
20
+ let next;
21
+ if (connector instanceof Array) {
22
+ if (connector.length === 0)
23
+ throw new Error('Connectors array must not be empty');
24
+ if (connector.length > 1) {
25
+ next = new Connector();
26
+ for (const item of connector) {
27
+ this.#dependencies.push(item);
28
+ item.depends(next);
29
+ }
30
+ }
31
+ else
32
+ next = connector[0];
33
+ }
34
+ else
35
+ next = connector;
36
+ this.#dependencies.push(next);
37
+ next.link(this);
38
+ return next;
39
+ }
40
+ /**
41
+ * Creates a backlink to another Connector
42
+ *
43
+ * See .connect() and .disconnect()
44
+ *
45
+ */
46
+ link(connector) {
47
+ this.#links.push(connector);
48
+ }
49
+ /**
50
+ * Connects dependants then self
51
+ *
52
+ * In case of exception disconnects with current connection interruption
53
+ *
54
+ * Method is idempotent
55
+ *
56
+ */
57
+ async connect() {
58
+ if (this.#connecting)
59
+ return this.#connecting;
60
+ this.#disconnecting = undefined;
61
+ const work = async () => {
62
+ await Promise.all(this.#dependencies.map((connector) => connector.connect()));
63
+ await this.open();
64
+ };
65
+ // anonymous grouping nodes are not worth a span
66
+ this.#connecting =
67
+ TRACE_BOOT && this.constructor.name !== 'Connector'
68
+ ? console.span({
69
+ name: `connect ${this.constructor.name}`,
70
+ // a connector that has a locator is named by it; a grouping node has none
71
+ attributes: { id: this.locator?.id ?? this.id }
72
+ }, work)
73
+ : work();
74
+ try {
75
+ await this.#connecting;
76
+ this.connected = true;
77
+ }
78
+ catch (e) {
79
+ await this.disconnect(true);
80
+ throw e;
81
+ }
82
+ }
83
+ /**
84
+ * Disconnects self then dependants
85
+ *
86
+ * Does nothing if there are connected linked Connectors
87
+ *
88
+ * Method is idempotent
89
+ *
90
+ */
91
+ async disconnect(interrupt) {
92
+ // a connector that has not finished connecting has nothing to close, and
93
+ // awaiting a connection that may never settle outlives any grace period
94
+ const pending = interrupt === true || this.connected === false;
95
+ if (!pending)
96
+ await this.#connecting;
97
+ if (this.#disconnecting)
98
+ return this.#disconnecting;
99
+ const linked = this.#links.reduce((acc, parent) => acc || parent.connected, false);
100
+ if (linked && interrupt !== true)
101
+ return;
102
+ this.#disconnecting = (async () => {
103
+ const start = +new Date();
104
+ const interval = setInterval(() => {
105
+ const delay = +new Date() - start;
106
+ if (delay > DELAY)
107
+ console.warn(`Connector ${this.id} still disconnecting (${delay})`);
108
+ }, DELAY);
109
+ if (!pending)
110
+ await this.close();
111
+ // said once the closing is done rather than when it starts: a dependant that is
112
+ // still closing is still using what it depends on, and the check above reads this
113
+ // of every dependant. Saying it early lets the first to start tear down a shared
114
+ // dependency under the others.
115
+ this.connected = false;
116
+ this.#connecting = undefined;
117
+ clearInterval(interval);
118
+ await Promise.all(this.#dependencies.map((connector) => connector.disconnect()));
119
+ await this.dispose();
120
+ })();
121
+ await this.#disconnecting;
122
+ }
123
+ async reconnect() {
124
+ await this.disconnect();
125
+ await this.connect();
126
+ }
127
+ debug(node = {}) {
128
+ node[this.id] = { connected: this.connected };
129
+ if (this.#dependencies.length > 0)
130
+ for (const connector of this.#dependencies)
131
+ connector.debug?.(node[this.id]);
132
+ return node;
133
+ }
134
+ /** Called on connection */
135
+ open() { }
136
+ /** Called on disconnection */
137
+ close() { }
138
+ /** Called after self and dependants disconnection is complete */
139
+ dispose() { }
140
+ }
141
+ const DELAY = 5000;
142
+ const TRACE_BOOT = process.env.TOA_BOOT_TRACE === '1';
143
+ //# 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,18 @@
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 { 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
+ readonly aspects: Aspect[];
13
+ readonly locator: Locator;
14
+ constructor(local: Component, discover: Discover, aspects?: Aspect[]);
15
+ apply(endpoint: string, request: Request): Promise<any>;
16
+ call(namespace: string, name: string, endpoint: string, request: Request): Promise<any>;
17
+ }
18
+ export {};
@@ -0,0 +1,41 @@
1
+ import { Connector } from './connector.js';
2
+ export class Context extends Connector {
3
+ env;
4
+ name;
5
+ aspects;
6
+ locator;
7
+ #local;
8
+ #discover;
9
+ #remotes = {};
10
+ constructor(local, discover, aspects = []) {
11
+ super();
12
+ this.env = process.env.TOA_ENV;
13
+ this.name = process.env.TOA_CONTEXT;
14
+ this.aspects = aspects;
15
+ this.locator = local?.locator;
16
+ this.#local = local;
17
+ this.#discover = discover;
18
+ this.depends(local);
19
+ if (aspects.length > 0)
20
+ this.depends(aspects);
21
+ }
22
+ async apply(endpoint, request) {
23
+ return this.#local.invoke(endpoint, request);
24
+ }
25
+ // eslint-disable-next-line max-params
26
+ async call(namespace, name, endpoint, request) {
27
+ const remote = await this.#remote(namespace, name);
28
+ return remote.invoke(endpoint, request);
29
+ }
30
+ async #remote(namespace, name) {
31
+ const key = namespace + '.' + name;
32
+ this.#remotes[key] ??= this.#connect(namespace, name);
33
+ return this.#remotes[key];
34
+ }
35
+ async #connect(namespace, name) {
36
+ const remote = await this.#discover(namespace, name);
37
+ this.depends(remote);
38
+ return remote;
39
+ }
40
+ }
41
+ //# 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;AAS1C,MAAM,OAAO,OAAQ,SAAQ,SAAS;IACpB,GAAG,CAAoB;IACvB,IAAI,CAAoB;IACxB,OAAO,CAAU;IACjB,OAAO,CAAS;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,OAAO,CAAC,GAAG,CAAC,OAAO,CAAA;QAC9B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAA;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,EAAE,OAAO,CAAA;QAE7B,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;QACnD,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC9C,CAAC;IAED,sCAAsC;IAC/B,KAAK,CAAC,IAAI,CACf,SAAiB,EACjB,IAAY,EACZ,QAAgB,EAChB,OAAgB;QAEhB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QAElD,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IACzC,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,24 @@
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
+ input?: JSONSchema | null;
9
+ output?: JSONSchema | null;
10
+ errors?: Array<string | number>;
11
+ }
12
+ export interface Definition extends Explanation {
13
+ type?: string;
14
+ scope?: string;
15
+ query?: boolean;
16
+ }
17
+ export declare class Request extends Contract {
18
+ readonly discovery: Explanation;
19
+ static Exception: Refusal;
20
+ constructor(schema: Schema, definition: Definition);
21
+ static schema(definition: Definition, entity?: {
22
+ properties: Record<string, JSONSchema>;
23
+ }): JSONSchema;
24
+ }
@@ -0,0 +1,59 @@
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) {
8
+ super(schema);
9
+ for (const key of ['description', 'input', 'output', 'errors'])
10
+ if (definition[key] !== undefined)
11
+ this.discovery[key] = definition[key];
12
+ }
13
+ static schema(definition, entity) {
14
+ // `source` is not among these: the framework stamps it and whoever reads it takes the keys
15
+ // it knows, so holding it to a schema would only fail calls from a peer that stamps one more
16
+ const schema = {
17
+ type: 'object',
18
+ properties: {
19
+ authentic: { type: 'boolean' },
20
+ task: { type: 'boolean' }
21
+ },
22
+ additionalProperties: true
23
+ };
24
+ const required = [];
25
+ if (definition.input !== undefined) {
26
+ schema.properties.input = definition.input;
27
+ required.push('input');
28
+ }
29
+ else
30
+ schema.properties.input = { type: 'null' };
31
+ if (entity === undefined)
32
+ definition.query = false;
33
+ if (definition.query === true)
34
+ required.push('query');
35
+ if (definition.query === false)
36
+ schema.properties.query = { type: 'null' };
37
+ if (definition.query !== false) {
38
+ const query = structuredClone(schemas.query);
39
+ query.properties.id = entity?.properties.id;
40
+ if (definition.type === 'observation')
41
+ delete query.properties.version;
42
+ else
43
+ delete query.properties.projection;
44
+ if (definition.type !== 'observation' || definition.scope !== 'objects') {
45
+ delete query.properties.omit;
46
+ delete query.properties.limit;
47
+ }
48
+ else if (query.required === undefined)
49
+ query.required = ['limit'];
50
+ else
51
+ query.required.push('limit');
52
+ schema.properties.query = query;
53
+ }
54
+ if (required.length > 0)
55
+ schema.required = required;
56
+ return schema;
57
+ }
58
+ }
59
+ //# sourceMappingURL=request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../source/contract/request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAmBxC,MAAM,OAAO,OAAQ,SAAQ,QAAQ;IACnB,SAAS,GAAgB,EAAE,CAAA;IAEpC,MAAM,CAAU,SAAS,GAC9B,wBAA8C,CAAA;IAEhD,YAAmB,MAAc,EAAE,UAAsB;QACvD,KAAK,CAAC,MAAM,CAAC,CAAA;QAEb,KAAK,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAU;YACrE,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,SAAS;gBAC9B,IAAI,CAAC,SAAqC,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAA;IACxE,CAAC;IAEM,MAAM,CAAC,MAAM,CAClB,UAAsB,EACtB,MAAmD;QAEnD,2FAA2F;QAC3F,6FAA6F;QAC7F,MAAM,MAAM,GAAe;YACzB,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;gBAC9B,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;aAC1B;YACD,oBAAoB,EAAE,IAAI;SAC3B,CAAA;QAED,MAAM,QAAQ,GAAa,EAAE,CAAA;QAE7B,IAAI,UAAU,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,CAAC,UAAU,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAA;YAC1C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACxB,CAAC;;YAAM,MAAM,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QAEjD,IAAI,MAAM,KAAK,SAAS;YAAE,UAAU,CAAC,KAAK,GAAG,KAAK,CAAA;QAElD,IAAI,UAAU,CAAC,KAAK,KAAK,IAAI;YAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAErD,IAAI,UAAU,CAAC,KAAK,KAAK,KAAK;YAAE,MAAM,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QAE1E,IAAI,UAAU,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;YAE5C,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,CAAC,EAAE,CAAA;YAE3C,IAAI,UAAU,CAAC,IAAI,KAAK,aAAa;gBAAE,OAAO,KAAK,CAAC,UAAU,CAAC,OAAO,CAAA;;gBACjE,OAAO,KAAK,CAAC,UAAU,CAAC,UAAU,CAAA;YAEvC,IAAI,UAAU,CAAC,IAAI,KAAK,aAAa,IAAI,UAAU,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxE,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAA;gBAC5B,OAAO,KAAK,CAAC,UAAU,CAAC,KAAK,CAAA;YAC/B,CAAC;iBAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;gBAAE,KAAK,CAAC,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAA;;gBAC9D,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAEjC,MAAM,CAAC,UAAU,CAAC,KAAK,GAAG,KAAK,CAAA;QACjC,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAA;QAEnD,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
@@ -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,12 @@
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
+ lookup(locator: Locator): Promise<any>;
11
+ }
12
+ export {};
@@ -0,0 +1,34 @@
1
+ import { console } from 'openspan';
2
+ import { Connector } from './connector.js';
3
+ export class Discovery extends Connector {
4
+ #lookup;
5
+ #lookups = {};
6
+ constructor(lookup) {
7
+ super();
8
+ this.#lookup = lookup;
9
+ }
10
+ async open() {
11
+ this.#lookups = {};
12
+ }
13
+ async lookup(locator) {
14
+ const id = locator.id;
15
+ if (this.#lookups[id] === undefined) {
16
+ const lookup = await this.#lookup(locator);
17
+ this.#lookups[id] = Promise.resolve(lookup);
18
+ this.depends(lookup);
19
+ }
20
+ const since = Date.now();
21
+ // the wait is unbounded by design, as a dependency may still be starting,
22
+ // so repeating is the only way a component stuck on one stays visible
23
+ const warning = setInterval(() => {
24
+ const waiting = Math.round((Date.now() - since) / 1000);
25
+ console.warn('Waiting for lookup response', { component: id, waiting });
26
+ }, INTERVAL);
27
+ warning.unref();
28
+ const output = await (await this.#lookups[id]).invoke();
29
+ clearInterval(warning);
30
+ return output;
31
+ }
32
+ }
33
+ const INTERVAL = 5000;
34
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../source/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAO1C,MAAM,OAAO,SAAU,SAAQ,SAAS;IAC7B,OAAO,CAAuC;IACvD,QAAQ,GAAoC,EAAE,CAAA;IAE9C,YAAmB,MAA6C;QAC9D,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;IACvB,CAAC;IAEkB,KAAK,CAAC,IAAI;QAC3B,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA;IACpB,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,OAAgB;QAClC,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,CAAA;QAErB,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,SAAS,EAAE,CAAC;YACpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;YAE1C,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YAC3C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QACtB,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAExB,0EAA0E;QAC1E,sEAAsE;QACtE,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;YAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,CAAA;YAEvD,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;QACzE,CAAC,EAAE,QAAQ,CAAC,CAAA;QAEZ,OAAO,CAAC,KAAK,EAAE,CAAA;QAEf,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAA;QAEvD,aAAa,CAAC,OAAO,CAAC,CAAA;QAEtB,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AAED,MAAM,QAAQ,GAAG,IAAI,CAAA"}
@@ -0,0 +1,5 @@
1
+ import { Observation } from './observation.js';
2
+ import type { Store } from './operation.js';
3
+ export declare class Effect extends Observation {
4
+ protected acquire(store: Store): Promise<void>;
5
+ }
@@ -0,0 +1,11 @@
1
+ import { Observation } from './observation.js';
2
+ export class Effect extends Observation {
3
+ async acquire(store) {
4
+ const { query, entity, input } = store.request;
5
+ if (entity === undefined)
6
+ return super.acquire(store);
7
+ store.scope = await this.scope.ensure(query, entity, input);
8
+ store.state = store.scope.get();
9
+ }
10
+ }
11
+ //# sourceMappingURL=effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect.js","sourceRoot":"","sources":["../source/effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAI9C,MAAM,OAAO,MAAO,SAAQ,WAAW;IAClB,KAAK,CAAC,OAAO,CAAC,KAAY;QAC3C,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,OAAO,CAAA;QAE9C,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAErD,KAAK,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAY,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;QAClE,KAAK,CAAC,KAAK,GAAI,KAAK,CAAC,KAAgB,CAAC,GAAG,EAAE,CAAA;IAC7C,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import { Connector } from './connector.js';
2
+ import type { Event } from './event.js';
3
+ import type { Event as StateEvent } from './types/state.js';
4
+ export declare class Emission extends Connector {
5
+ #private;
6
+ constructor(events: Event[]);
7
+ emit(event: StateEvent): Promise<void>;
8
+ }
@@ -0,0 +1,14 @@
1
+ import { Connector } from './connector.js';
2
+ export class Emission extends Connector {
3
+ #events;
4
+ constructor(events) {
5
+ super();
6
+ this.#events = events;
7
+ this.depends(events);
8
+ }
9
+ async emit(event) {
10
+ const emission = this.#events.map((e) => e.emit(event));
11
+ await Promise.all(emission);
12
+ }
13
+ }
14
+ //# sourceMappingURL=emission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emission.js","sourceRoot":"","sources":["../source/emission.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAI1C,MAAM,OAAO,QAAS,SAAQ,SAAS;IAC5B,OAAO,CAAS;IAEzB,YAAmB,MAAe;QAChC,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QAErB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IACtB,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,KAAiB;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;QAEvD,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC7B,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import type { Schema } from '@toa.io/schemas';
2
+ import type { Query, Record } from '../types/storages.js';
3
+ export declare class Changeset {
4
+ #private;
5
+ readonly query: Query;
6
+ constructor(schema: Schema, query: Query);
7
+ get(): object;
8
+ set(value: Record): void;
9
+ export(): object;
10
+ }
@@ -0,0 +1,27 @@
1
+ import { EntityContractException } from '../exceptions.js';
2
+ export class Changeset {
3
+ query;
4
+ /** the changeset schema: the entity's properties, none of them required */
5
+ #schema;
6
+ #state;
7
+ constructor(schema, query) {
8
+ this.query = query;
9
+ this.#schema = schema;
10
+ this.#state = {};
11
+ }
12
+ get() {
13
+ return this.#state;
14
+ }
15
+ set(value) {
16
+ const error = this.#schema.fit(value);
17
+ if (error !== null)
18
+ throw new EntityContractException(error, value);
19
+ delete value.VERSION;
20
+ value.UPDATED = Date.now();
21
+ this.#state = value;
22
+ }
23
+ export() {
24
+ return this.#state;
25
+ }
26
+ }
27
+ //# sourceMappingURL=changeset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changeset.js","sourceRoot":"","sources":["../../source/entities/changeset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;AAI1D,MAAM,OAAO,SAAS;IACJ,KAAK,CAAO;IAE5B,2EAA2E;IAClE,OAAO,CAAQ;IACxB,MAAM,CAAiB;IAEvB,YAAmB,MAAc,EAAE,KAAY;QAC7C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAElB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;IAClB,CAAC;IAEM,GAAG;QACR,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IAEM,GAAG,CAAC,KAAa;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAErC,IAAI,KAAK,KAAK,IAAI;YAAE,MAAM,IAAI,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAEnE,OAAQ,KAAyB,CAAC,OAAO,CAAA;QACzC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAE1B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;IACrB,CAAC;IAEM,MAAM;QACX,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ import type { Schema } from '@toa.io/schemas';
2
+ import type { Guard } from '../guard.js';
3
+ import type { Record } from '../types/storages.js';
4
+ import type { Event } from '../types/state.js';
5
+ export declare class Entity {
6
+ #private;
7
+ deleted: boolean;
8
+ /**
9
+ * A record makes an entity of what a storage holds; a string, or nothing at all, makes a
10
+ * blank one under that identity, out of what the component declared a record starts as.
11
+ *
12
+ * @param blank what the component declares a record holds before anything is written to it
13
+ * @param mutable whether the entity may be modified and committed
14
+ */
15
+ constructor(schema: Schema, blank: object, argument?: Record | string, guards?: Guard[], mutable?: boolean);
16
+ get(): Record;
17
+ set(value: Record): void;
18
+ event(input?: object): Event;
19
+ }