@toa.io/core 1.0.0-alpha.29 → 1.0.0-alpha.291

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 (304) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/package.json +22 -12
  3. package/source/assignment.ts +27 -0
  4. package/source/call.ts +63 -0
  5. package/source/cascade.ts +32 -0
  6. package/source/component.ts +83 -0
  7. package/source/composition.ts +27 -0
  8. package/source/connector.ts +217 -0
  9. package/source/context.ts +68 -0
  10. package/source/contract/contract.ts +23 -0
  11. package/source/contract/index.ts +2 -0
  12. package/source/contract/reply.ts +56 -0
  13. package/source/contract/request.ts +140 -0
  14. package/source/contract/schemas.ts +39 -0
  15. package/source/discovery.ts +53 -0
  16. package/source/effect.ts +14 -0
  17. package/source/emission.ts +21 -0
  18. package/source/entities/changeset.ts +37 -0
  19. package/source/entities/entity.ts +137 -0
  20. package/source/entities/factory.ts +52 -0
  21. package/source/entities/index.ts +4 -0
  22. package/source/entities/newid.ts +9 -0
  23. package/source/entities/set.ts +27 -0
  24. package/source/event.ts +57 -0
  25. package/source/exceptions.ts +133 -0
  26. package/source/exposition.ts +33 -0
  27. package/source/guard.ts +16 -0
  28. package/source/index.ts +36 -0
  29. package/source/locator.ts +37 -0
  30. package/source/observation.ts +16 -0
  31. package/source/operation.ts +139 -0
  32. package/source/outbox/index.ts +1 -0
  33. package/source/outbox/outbox.ts +341 -0
  34. package/source/query/criteria.ts +90 -0
  35. package/source/query/options.ts +35 -0
  36. package/source/query.ts +67 -0
  37. package/source/receiver.ts +120 -0
  38. package/source/reflection.ts +20 -0
  39. package/source/remote.ts +20 -0
  40. package/source/state.ts +179 -0
  41. package/source/transition.ts +79 -0
  42. package/source/transmission.ts +38 -0
  43. package/source/types/atomicity.ts +63 -0
  44. package/source/types/bindings.ts +59 -0
  45. package/source/types/bridges.ts +54 -0
  46. package/source/types/extensions.ts +89 -0
  47. package/source/types/index.ts +14 -0
  48. package/{types/message.d.ts → source/types/message.ts} +2 -0
  49. package/source/types/operations.ts +31 -0
  50. package/source/types/outbox.ts +35 -0
  51. package/source/types/receiver.ts +10 -0
  52. package/source/types/request.ts +54 -0
  53. package/source/types/state.ts +9 -0
  54. package/source/types/storages.ts +134 -0
  55. package/source/unmanaged.ts +8 -0
  56. package/test/call.fixtures.js +10 -12
  57. package/test/call.test.js +42 -9
  58. package/test/component.fixtures.js +5 -8
  59. package/test/component.test.js +27 -10
  60. package/test/connector.fixtures.js +29 -13
  61. package/test/connector.test.js +128 -38
  62. package/test/context.fixtures.js +8 -12
  63. package/test/context.test.js +19 -8
  64. package/test/contract/conditions.test.js +15 -9
  65. package/test/contract/contract.fixtures.js +11 -16
  66. package/test/contract/request.test.js +130 -46
  67. package/test/discovery.test.js +71 -0
  68. package/test/emission.fixtures.js +6 -10
  69. package/test/emission.test.js +37 -12
  70. package/test/entities/entity.fixtures.js +11 -16
  71. package/test/entities/entity.test.js +105 -50
  72. package/test/entities/factory.fixtures.js +26 -13
  73. package/test/entities/factory.test.js +68 -17
  74. package/test/entities/set.fixtures.js +6 -8
  75. package/test/entities/set.test.js +6 -5
  76. package/test/event.fixtures.js +9 -14
  77. package/test/event.test.js +78 -34
  78. package/test/locator.test.js +32 -25
  79. package/test/outbox.test.js +202 -0
  80. package/test/query.fixtures.js +1 -5
  81. package/test/query.test.js +111 -14
  82. package/test/receiver.fixtures.js +9 -12
  83. package/test/receiver.test.js +80 -31
  84. package/test/reflection.test.js +9 -8
  85. package/test/state.fixtures.js +33 -31
  86. package/test/state.test.js +135 -19
  87. package/test/transmission.fixtures.js +4 -6
  88. package/test/transmission.test.js +47 -16
  89. package/transpiled/assignment.d.ts +6 -0
  90. package/transpiled/assignment.js +20 -0
  91. package/transpiled/assignment.js.map +1 -0
  92. package/transpiled/call.d.ts +10 -0
  93. package/transpiled/call.js +52 -0
  94. package/transpiled/call.js.map +1 -0
  95. package/transpiled/cascade.d.ts +7 -0
  96. package/transpiled/cascade.js +28 -0
  97. package/transpiled/cascade.js.map +1 -0
  98. package/transpiled/component.d.ts +15 -0
  99. package/transpiled/component.js +61 -0
  100. package/transpiled/component.js.map +1 -0
  101. package/transpiled/composition.d.ts +6 -0
  102. package/transpiled/composition.js +23 -0
  103. package/transpiled/composition.js.map +1 -0
  104. package/transpiled/connector.d.ts +47 -0
  105. package/transpiled/connector.js +185 -0
  106. package/transpiled/connector.js.map +1 -0
  107. package/transpiled/context.d.ts +18 -0
  108. package/transpiled/context.js +42 -0
  109. package/transpiled/context.js.map +1 -0
  110. package/transpiled/contract/contract.d.ts +10 -0
  111. package/transpiled/contract/contract.js +14 -0
  112. package/transpiled/contract/contract.js.map +1 -0
  113. package/transpiled/contract/index.d.ts +2 -0
  114. package/transpiled/contract/index.js +3 -0
  115. package/transpiled/contract/index.js.map +1 -0
  116. package/transpiled/contract/reply.d.ts +7 -0
  117. package/transpiled/contract/reply.js +48 -0
  118. package/transpiled/contract/reply.js.map +1 -0
  119. package/transpiled/contract/request.d.ts +29 -0
  120. package/transpiled/contract/request.js +103 -0
  121. package/transpiled/contract/request.js.map +1 -0
  122. package/transpiled/contract/schemas.d.ts +4 -0
  123. package/transpiled/contract/schemas.js +36 -0
  124. package/transpiled/contract/schemas.js.map +1 -0
  125. package/transpiled/discovery.d.ts +12 -0
  126. package/transpiled/discovery.js +34 -0
  127. package/transpiled/discovery.js.map +1 -0
  128. package/transpiled/effect.d.ts +5 -0
  129. package/transpiled/effect.js +11 -0
  130. package/transpiled/effect.js.map +1 -0
  131. package/transpiled/emission.d.ts +8 -0
  132. package/transpiled/emission.js +14 -0
  133. package/transpiled/emission.js.map +1 -0
  134. package/transpiled/entities/changeset.d.ts +10 -0
  135. package/transpiled/entities/changeset.js +27 -0
  136. package/transpiled/entities/changeset.js.map +1 -0
  137. package/transpiled/entities/entity.d.ts +19 -0
  138. package/transpiled/entities/entity.js +109 -0
  139. package/transpiled/entities/entity.js.map +1 -0
  140. package/transpiled/entities/factory.d.ts +22 -0
  141. package/transpiled/entities/factory.js +34 -0
  142. package/transpiled/entities/factory.js.map +1 -0
  143. package/transpiled/entities/index.d.ts +4 -0
  144. package/transpiled/entities/index.js +5 -0
  145. package/transpiled/entities/index.js.map +1 -0
  146. package/transpiled/entities/newid.d.ts +1 -0
  147. package/transpiled/entities/newid.js +7 -0
  148. package/transpiled/entities/newid.js.map +1 -0
  149. package/transpiled/entities/set.d.ts +10 -0
  150. package/transpiled/entities/set.js +19 -0
  151. package/transpiled/entities/set.js.map +1 -0
  152. package/transpiled/event.d.ts +14 -0
  153. package/transpiled/event.js +38 -0
  154. package/transpiled/event.js.map +1 -0
  155. package/transpiled/exceptions.d.ts +61 -0
  156. package/transpiled/exceptions.js +93 -0
  157. package/transpiled/exceptions.js.map +1 -0
  158. package/transpiled/exposition.d.ts +18 -0
  159. package/transpiled/exposition.js +18 -0
  160. package/transpiled/exposition.js.map +1 -0
  161. package/transpiled/guard.d.ts +7 -0
  162. package/transpiled/guard.js +12 -0
  163. package/transpiled/guard.js.map +1 -0
  164. package/transpiled/index.d.ts +35 -0
  165. package/transpiled/index.js +29 -0
  166. package/transpiled/index.js.map +1 -0
  167. package/transpiled/locator.d.ts +12 -0
  168. package/transpiled/locator.js +32 -0
  169. package/transpiled/locator.js.map +1 -0
  170. package/transpiled/observation.d.ts +5 -0
  171. package/transpiled/observation.js +12 -0
  172. package/transpiled/observation.js.map +1 -0
  173. package/transpiled/operation.d.ts +49 -0
  174. package/transpiled/operation.js +78 -0
  175. package/transpiled/operation.js.map +1 -0
  176. package/transpiled/outbox/index.d.ts +1 -0
  177. package/transpiled/outbox/index.js +2 -0
  178. package/transpiled/outbox/index.js.map +1 -0
  179. package/transpiled/outbox/outbox.d.ts +46 -0
  180. package/transpiled/outbox/outbox.js +268 -0
  181. package/transpiled/outbox/outbox.js.map +1 -0
  182. package/transpiled/query/criteria.d.ts +6 -0
  183. package/transpiled/query/criteria.js +74 -0
  184. package/transpiled/query/criteria.js.map +1 -0
  185. package/transpiled/query/options.d.ts +3 -0
  186. package/transpiled/query/options.js +27 -0
  187. package/transpiled/query/options.js.map +1 -0
  188. package/transpiled/query.d.ts +9 -0
  189. package/transpiled/query.js +57 -0
  190. package/transpiled/query.js.map +1 -0
  191. package/transpiled/receiver.d.ts +20 -0
  192. package/transpiled/receiver.js +92 -0
  193. package/transpiled/receiver.js.map +1 -0
  194. package/transpiled/reflection.d.ts +9 -0
  195. package/transpiled/reflection.js +13 -0
  196. package/transpiled/reflection.js.map +1 -0
  197. package/transpiled/remote.d.ts +10 -0
  198. package/transpiled/remote.js +12 -0
  199. package/transpiled/remote.js.map +1 -0
  200. package/transpiled/state.d.ts +33 -0
  201. package/transpiled/state.js +126 -0
  202. package/transpiled/state.js.map +1 -0
  203. package/transpiled/transition.d.ts +14 -0
  204. package/transpiled/transition.js +51 -0
  205. package/transpiled/transition.js.map +1 -0
  206. package/transpiled/transmission.d.ts +8 -0
  207. package/transpiled/transmission.js +30 -0
  208. package/transpiled/transmission.js.map +1 -0
  209. package/transpiled/types/atomicity.d.ts +56 -0
  210. package/transpiled/types/atomicity.js +2 -0
  211. package/transpiled/types/atomicity.js.map +1 -0
  212. package/transpiled/types/bindings.d.ts +42 -0
  213. package/transpiled/types/bindings.js +2 -0
  214. package/transpiled/types/bindings.js.map +1 -0
  215. package/transpiled/types/bridges.d.ts +38 -0
  216. package/transpiled/types/bridges.js +2 -0
  217. package/transpiled/types/bridges.js.map +1 -0
  218. package/transpiled/types/extensions.d.ts +62 -0
  219. package/transpiled/types/extensions.js +2 -0
  220. package/transpiled/types/extensions.js.map +1 -0
  221. package/transpiled/types/index.d.ts +13 -0
  222. package/transpiled/types/index.js +8 -0
  223. package/transpiled/types/index.js.map +1 -0
  224. package/transpiled/types/message.d.ts +5 -0
  225. package/transpiled/types/message.js +2 -0
  226. package/transpiled/types/message.js.map +1 -0
  227. package/transpiled/types/operations.d.ts +15 -0
  228. package/transpiled/types/operations.js +2 -0
  229. package/transpiled/types/operations.js.map +1 -0
  230. package/transpiled/types/outbox.d.ts +28 -0
  231. package/transpiled/types/outbox.js +2 -0
  232. package/transpiled/types/outbox.js.map +1 -0
  233. package/transpiled/types/receiver.d.ts +9 -0
  234. package/transpiled/types/receiver.js +2 -0
  235. package/transpiled/types/receiver.js.map +1 -0
  236. package/transpiled/types/request.d.ts +55 -0
  237. package/transpiled/types/request.js +2 -0
  238. package/transpiled/types/request.js.map +1 -0
  239. package/transpiled/types/state.d.ts +9 -0
  240. package/transpiled/types/state.js +2 -0
  241. package/transpiled/types/state.js.map +1 -0
  242. package/transpiled/types/storages.d.ts +111 -0
  243. package/transpiled/types/storages.js +2 -0
  244. package/transpiled/types/storages.js.map +1 -0
  245. package/transpiled/unmanaged.d.ts +5 -0
  246. package/transpiled/unmanaged.js +7 -0
  247. package/transpiled/unmanaged.js.map +1 -0
  248. package/tsconfig.json +10 -0
  249. package/tsconfig.tsbuildinfo +1 -0
  250. package/src/assignment.js +0 -31
  251. package/src/call.js +0 -42
  252. package/src/cascade.js +0 -36
  253. package/src/component.js +0 -41
  254. package/src/composition.js +0 -25
  255. package/src/connector.js +0 -183
  256. package/src/context.js +0 -55
  257. package/src/contract/conditions.js +0 -21
  258. package/src/contract/index.js +0 -7
  259. package/src/contract/reply.js +0 -25
  260. package/src/contract/request.js +0 -67
  261. package/src/contract/schemas/error.yaml +0 -9
  262. package/src/contract/schemas/index.js +0 -7
  263. package/src/contract/schemas/query.yaml +0 -30
  264. package/src/discovery.js +0 -44
  265. package/src/emission.js +0 -23
  266. package/src/entities/changeset.js +0 -43
  267. package/src/entities/entity.js +0 -73
  268. package/src/entities/factory.js +0 -33
  269. package/src/entities/index.js +0 -5
  270. package/src/entities/set.js +0 -15
  271. package/src/event.js +0 -40
  272. package/src/exceptions.js +0 -100
  273. package/src/exposition.js +0 -27
  274. package/src/index.js +0 -47
  275. package/src/locator.js +0 -54
  276. package/src/observation.js +0 -20
  277. package/src/operation.js +0 -69
  278. package/src/query/criteria.js +0 -41
  279. package/src/query/options.js +0 -40
  280. package/src/query.js +0 -41
  281. package/src/receiver.js +0 -65
  282. package/src/reflection.js +0 -28
  283. package/src/remote.js +0 -17
  284. package/src/state.js +0 -99
  285. package/src/transition.js +0 -73
  286. package/src/transmission.js +0 -33
  287. package/types/bindings.d.ts +0 -40
  288. package/types/bridges.ts +0 -30
  289. package/types/component.d.ts +0 -9
  290. package/types/connector.d.ts +0 -18
  291. package/types/context.d.ts +0 -21
  292. package/types/entity.d.ts +0 -46
  293. package/types/event.d.ts +0 -11
  294. package/types/exception.d.ts +0 -4
  295. package/types/extensions.d.ts +0 -29
  296. package/types/index.ts +0 -14
  297. package/types/locator.d.ts +0 -13
  298. package/types/operations.d.ts +0 -2
  299. package/types/query.d.ts +0 -15
  300. package/types/receiver.d.ts +0 -12
  301. package/types/reflection.d.ts +0 -14
  302. package/types/request.d.ts +0 -23
  303. package/types/state.d.ts +0 -35
  304. package/types/storages.d.ts +0 -71
@@ -0,0 +1,35 @@
1
+ export { Assignment } from './assignment.js';
2
+ export { Call } from './call.js';
3
+ export { Cascade } from './cascade.js';
4
+ export { Component } from './component.js';
5
+ export { Composition } from './composition.js';
6
+ export { Connector } from './connector.js';
7
+ export { Context } from './context.js';
8
+ export { Discovery } from './discovery.js';
9
+ export { Effect } from './effect.js';
10
+ export { Emission } from './emission.js';
11
+ export { Event } from './event.js';
12
+ export { Exposition } from './exposition.js';
13
+ export { Locator } from './locator.js';
14
+ export { Observation } from './observation.js';
15
+ export { Outbox } from './outbox/index.js';
16
+ export { Operation } from './operation.js';
17
+ export { Query } from './query.js';
18
+ export { Receiver } from './receiver.js';
19
+ export { Reflection } from './reflection.js';
20
+ export { Remote } from './remote.js';
21
+ export { State } from './state.js';
22
+ export { Transition } from './transition.js';
23
+ export { Transmission } from './transmission.js';
24
+ export { Unmanaged } from './unmanaged.js';
25
+ export { Guard } from './guard.js';
26
+ export * as entities from './entities/index.js';
27
+ export * as exceptions from './exceptions.js';
28
+ export * as contract from './contract/index.js';
29
+ export type { Exception } from './exceptions.js';
30
+ export type { Invocable } from './component.js';
31
+ export type { Explicable } from './remote.js';
32
+ export type { Scoped, Store } from './operation.js';
33
+ export type { Source as ReflectionSource } from './reflection.js';
34
+ export type { Explanation } from './contract/request.js';
35
+ export type { JSONSchema } from './contract/schemas.js';
@@ -0,0 +1,29 @@
1
+ export { Assignment } from './assignment.js';
2
+ export { Call } from './call.js';
3
+ export { Cascade } from './cascade.js';
4
+ export { Component } from './component.js';
5
+ export { Composition } from './composition.js';
6
+ export { Connector } from './connector.js';
7
+ export { Context } from './context.js';
8
+ export { Discovery } from './discovery.js';
9
+ export { Effect } from './effect.js';
10
+ export { Emission } from './emission.js';
11
+ export { Event } from './event.js';
12
+ export { Exposition } from './exposition.js';
13
+ export { Locator } from './locator.js';
14
+ export { Observation } from './observation.js';
15
+ export { Outbox } from './outbox/index.js';
16
+ export { Operation } from './operation.js';
17
+ export { Query } from './query.js';
18
+ export { Receiver } from './receiver.js';
19
+ export { Reflection } from './reflection.js';
20
+ export { Remote } from './remote.js';
21
+ export { State } from './state.js';
22
+ export { Transition } from './transition.js';
23
+ export { Transmission } from './transmission.js';
24
+ export { Unmanaged } from './unmanaged.js';
25
+ export { Guard } from './guard.js';
26
+ export * as entities from './entities/index.js';
27
+ export * as exceptions from './exceptions.js';
28
+ export * as contract from './contract/index.js';
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAA;AAC/C,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,12 @@
1
+ /** Where a component is, as every name derived from it. */
2
+ export declare class Locator {
3
+ readonly name: string;
4
+ readonly namespace: string | undefined;
5
+ readonly id: string;
6
+ readonly label: string;
7
+ readonly uppercase: string;
8
+ readonly lowercase: string;
9
+ constructor(name: string, namespace?: string);
10
+ static parse(string: string): Locator;
11
+ hostname(prefix?: string): string;
12
+ }
@@ -0,0 +1,32 @@
1
+ import { concat } from '@toa.io/generic';
2
+ /** Where a component is, as every name derived from it. */
3
+ export class Locator {
4
+ name;
5
+ namespace;
6
+ id;
7
+ label;
8
+ uppercase;
9
+ lowercase;
10
+ constructor(name, namespace) {
11
+ if (name === undefined)
12
+ throw new TypeError('Locator name must be defined');
13
+ this.name = name;
14
+ this.namespace = namespace;
15
+ this.id = concat(namespace, '.') + name;
16
+ this.label = (concat(namespace, '-') + name).toLowerCase();
17
+ this.uppercase = (concat(namespace, '_') + name).toUpperCase();
18
+ this.lowercase = (concat(namespace, '_') + name).toLowerCase();
19
+ }
20
+ static parse(string) {
21
+ const [namespace, name] = string.split(DOT);
22
+ if (name === undefined)
23
+ return new Locator(namespace);
24
+ else
25
+ return new Locator(name, namespace);
26
+ }
27
+ hostname(prefix) {
28
+ return concat(prefix?.toLowerCase(), '-') + this.label;
29
+ }
30
+ }
31
+ const DOT = '.';
32
+ //# sourceMappingURL=locator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locator.js","sourceRoot":"","sources":["../source/locator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAExC,2DAA2D;AAC3D,MAAM,OAAO,OAAO;IACF,IAAI,CAAQ;IACZ,SAAS,CAAoB;IAE7B,EAAE,CAAQ;IACV,KAAK,CAAQ;IACb,SAAS,CAAQ;IACjB,SAAS,CAAQ;IAEjC,YAAmB,IAAY,EAAE,SAAkB;QACjD,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,SAAS,CAAC,8BAA8B,CAAC,CAAA;QAE3E,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAE1B,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,GAAG,IAAI,CAAA;QACvC,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAA;QAC1D,IAAI,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAA;QAC9D,IAAI,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAA;IAChE,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,MAAc;QAChC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAE3C,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC,CAAA;;YAChD,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;IAC1C,CAAC;IAEM,QAAQ,CAAC,MAAe;QAC7B,OAAO,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAA;IACxD,CAAC;CACF;AAED,MAAM,GAAG,GAAG,GAAG,CAAA"}
@@ -0,0 +1,5 @@
1
+ import { Operation } from './operation.js';
2
+ import type { Store } from './operation.js';
3
+ export declare class Observation extends Operation {
4
+ protected run(store: Store): Promise<void>;
5
+ }
@@ -0,0 +1,12 @@
1
+ import { Operation } from './operation.js';
2
+ export class Observation extends Operation {
3
+ async run(store) {
4
+ const scope = store.scope;
5
+ if (scope === null ||
6
+ (scope?.deleted === true && store.request.query?.options?.deleted !== true))
7
+ store.reply = null;
8
+ else
9
+ await super.run(store);
10
+ }
11
+ }
12
+ //# sourceMappingURL=observation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observation.js","sourceRoot":"","sources":["../source/observation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAI1C,MAAM,OAAO,WAAY,SAAQ,SAAS;IACrB,KAAK,CAAC,GAAG,CAAC,KAAY;QACvC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAsB,CAAA;QAE1C,IACE,KAAK,KAAK,IAAI;YACd,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,IAAK,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;YAEpF,KAAK,CAAC,KAAK,GAAG,IAAI,CAAA;;YACf,MAAM,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAC7B,CAAC;CACF"}
@@ -0,0 +1,49 @@
1
+ import { Readable } from 'node:stream';
2
+ import { Connector } from './connector.js';
3
+ import type { Cascade } from './cascade.js';
4
+ import type { State } from './state.js';
5
+ import type { Query as Translator } from './query.js';
6
+ import type { Contract } from './contract/contract.js';
7
+ import type { Entity } from './entities/entity.js';
8
+ import type { EntitySet } from './entities/set.js';
9
+ import type { Changeset } from './entities/changeset.js';
10
+ import type { scope as Scope } from './types/operations.js';
11
+ import type { Query, Request } from './types/request.js';
12
+ /** What an operation acquires for the algorithm to run against. */
13
+ export type Scoped = Entity | EntitySet | Changeset | Readable | null;
14
+ /** What one invocation carries from step to step. */
15
+ export interface Store {
16
+ request: Request;
17
+ scope?: Scoped;
18
+ state?: any;
19
+ reply?: any;
20
+ /** set by a transition, which is the only operation that runs its steps again */
21
+ retry?: () => Promise<any>;
22
+ }
23
+ export interface Contracts {
24
+ request: Contract;
25
+ reply: Contract;
26
+ }
27
+ export interface Definition {
28
+ scope: Scope;
29
+ concurrency?: string;
30
+ }
31
+ export declare class Operation extends Connector {
32
+ #private;
33
+ scope: State;
34
+ /**
35
+ * Whether what this operation acquires may be modified and committed. Only a
36
+ * transition commits, and only a commit needs the pre-image an entity keeps
37
+ * to diff the new state against.
38
+ *
39
+ * @protected
40
+ */
41
+ protected mutable: boolean;
42
+ constructor(cascade: Cascade, scope: State, contracts: Contracts, query: Translator, definition: Definition);
43
+ invoke(request: Request): Promise<any>;
44
+ protected process(store: Store): Promise<any>;
45
+ protected acquire(store: Store): Promise<void>;
46
+ protected run(store: Store): Promise<void>;
47
+ protected commit(_store: Store): Promise<void>;
48
+ protected query(query?: Query): Promise<Scoped>;
49
+ }
@@ -0,0 +1,78 @@
1
+ import { Readable } from 'node:stream';
2
+ import { Connector } from './connector.js';
3
+ import { SystemException, RequestContractException } from './exceptions.js';
4
+ import { environment } from '@toa.io/generic';
5
+ export class Operation extends Connector {
6
+ scope;
7
+ /**
8
+ * Whether what this operation acquires may be modified and committed. Only a
9
+ * transition commits, and only a commit needs the pre-image an entity keeps
10
+ * to diff the new state against.
11
+ *
12
+ * @protected
13
+ */
14
+ mutable = false;
15
+ #cascade;
16
+ #contracts;
17
+ #query;
18
+ #scope;
19
+ // eslint-disable-next-line max-params
20
+ constructor(cascade, scope, contracts, query, definition) {
21
+ super();
22
+ this.scope = scope;
23
+ this.#cascade = cascade;
24
+ this.#contracts = contracts;
25
+ this.#query = query;
26
+ this.#scope = definition.scope;
27
+ this.depends(cascade);
28
+ }
29
+ async invoke(request) {
30
+ try {
31
+ if (request.authentic !== true)
32
+ this.#contracts.request.fit(request);
33
+ // the request carries the query onward in its parsed form: what a storage is given,
34
+ // not what the caller sent
35
+ if ('query' in request)
36
+ request.query = this.#query.parse(request.query);
37
+ // validate entity
38
+ if ('entity' in request)
39
+ this.scope.fit(request.entity);
40
+ const store = { request };
41
+ return await this.process(store);
42
+ }
43
+ catch (e) {
44
+ const exception = e instanceof Error ? new SystemException(e) : e;
45
+ return { exception };
46
+ }
47
+ }
48
+ async process(store) {
49
+ await this.acquire(store);
50
+ await this.run(store);
51
+ await this.commit(store);
52
+ return store.reply;
53
+ }
54
+ async acquire(store) {
55
+ if (this.#scope === 'none')
56
+ return;
57
+ const scope = await this.query(store.request.query);
58
+ const raw = scope === null || scope instanceof Readable;
59
+ store.scope = scope;
60
+ store.state = raw ? scope : scope.get();
61
+ }
62
+ async run(store) {
63
+ const { request, state } = store;
64
+ const reply = await this.#cascade.run(request.input, state);
65
+ // validate reply only on local environments
66
+ if (environment.get('TOA_ENV') === 'local' && !(reply instanceof Readable))
67
+ this.#contracts.reply.fit(reply);
68
+ store.reply = reply;
69
+ }
70
+ async commit(_store) { }
71
+ async query(query) {
72
+ if (query === undefined)
73
+ throw new RequestContractException('Request query is required');
74
+ const acquire = this.scope[this.#scope];
75
+ return acquire.call(this.scope, query, this.mutable);
76
+ }
77
+ }
78
+ //# sourceMappingURL=operation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operation.js","sourceRoot":"","sources":["../source/operation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { Outbox, LANES } from './outbox.js';
@@ -0,0 +1,2 @@
1
+ export { Outbox, LANES } from './outbox.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/outbox/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,46 @@
1
+ import { Connector } from '../connector.js';
2
+ import type { Emission } from '../emission.js';
3
+ import type { Atom } from '../types/atomicity.js';
4
+ import type { Storage } from '../types/storages.js';
5
+ import type { Row } from '../types/outbox.js';
6
+ import type { Event } from '../types/state.js';
7
+ export interface Options {
8
+ interval?: number;
9
+ batch?: number;
10
+ gap?: number;
11
+ }
12
+ /**
13
+ * Owns the intent to publish. A row is built before the write so that the storage can commit
14
+ * it in the same transaction as the entity; publication then happens off the operation's path,
15
+ * and anything that fails to publish is recovered from the row.
16
+ *
17
+ * The mechanism is a safety net: in a healthy system the row is written, published within
18
+ * milliseconds by the same process, and marked published on that process's next tick.
19
+ *
20
+ * A storage that cannot commit a row atomically has no outbox, and this degrades to the
21
+ * inline emission it replaces.
22
+ */
23
+ export declare class Outbox extends Connector {
24
+ #private;
25
+ constructor(emission: Emission, storage: Storage | undefined, atom: Atom, options?: Options);
26
+ /** whether the storage can commit a row atomically with the entity */
27
+ get durable(): boolean;
28
+ /**
29
+ * An assignment's images are the write's own, so it hands over an event with neither, and
30
+ * the storage fills them in.
31
+ */
32
+ row(event: Partial<Event>): Row;
33
+ /**
34
+ * Hands a committed row over. Awaited by the caller only on the legacy path — with an
35
+ * outbox this returns at once and the broker leaves the operation's path.
36
+ */
37
+ publish(row: Row): Promise<void> | void;
38
+ protected open(): Promise<void>;
39
+ protected close(): Promise<void>;
40
+ }
41
+ /**
42
+ * Constant, never configuration: rows carry their lane, so lowering this would leave rows in
43
+ * lanes nobody reads any more. It is also the ceiling on replicas of one component, and a
44
+ * power of two so that the common replica counts divide evenly.
45
+ */
46
+ export declare const LANES = 128;
@@ -0,0 +1,268 @@
1
+ import { console } from 'openspan';
2
+ import { Connector } from '../connector.js';
3
+ import { newid } from '../entities/newid.js';
4
+ import { environment } from '@toa.io/generic';
5
+ /**
6
+ * Owns the intent to publish. A row is built before the write so that the storage can commit
7
+ * it in the same transaction as the entity; publication then happens off the operation's path,
8
+ * and anything that fails to publish is recovered from the row.
9
+ *
10
+ * The mechanism is a safety net: in a healthy system the row is written, published within
11
+ * milliseconds by the same process, and marked published on that process's next tick.
12
+ *
13
+ * A storage that cannot commit a row atomically has no outbox, and this degrades to the
14
+ * inline emission it replaces.
15
+ */
16
+ export class Outbox extends Connector {
17
+ #emission;
18
+ #storage;
19
+ #atom;
20
+ #gap;
21
+ #interval;
22
+ #batch;
23
+ #defer;
24
+ /** ids this process has published, held until a cycle marks them */
25
+ #published = new Set();
26
+ /** in-flight publications, awaited (with a bound) on close */
27
+ #inflight = new Set();
28
+ /** rows this replica is publishing right now, so a cycle does not pick them up again */
29
+ #publishing = new Set();
30
+ #timer;
31
+ #off;
32
+ #pumping = false;
33
+ #closing = false;
34
+ // eslint-disable-next-line max-params
35
+ constructor(emission, storage, atom, options = {}) {
36
+ super();
37
+ this.#emission = emission;
38
+ this.#storage = storage;
39
+ this.#atom = atom;
40
+ this.#interval = number('TOA_OUTBOX_INTERVAL', options.interval, INTERVAL);
41
+ this.#batch = number('TOA_OUTBOX_BATCH', options.batch, BATCH);
42
+ this.#gap = options.gap ?? this.#interval * K;
43
+ this.#defer = environment.get('TOA_OUTBOX_DEFER') === '1';
44
+ this.depends(emission);
45
+ this.depends(atom);
46
+ if (storage !== undefined)
47
+ this.depends(storage);
48
+ }
49
+ /** whether the storage can commit a row atomically with the entity */
50
+ get durable() {
51
+ return this.#storage?.outbox !== undefined;
52
+ }
53
+ /**
54
+ * An assignment's images are the write's own, so it hands over an event with neither, and
55
+ * the storage fills them in.
56
+ */
57
+ row(event) {
58
+ return {
59
+ id: newid(),
60
+ lane: this.#lane(),
61
+ published: false,
62
+ pending: Date.now() + this.#gap,
63
+ event: event
64
+ };
65
+ }
66
+ /**
67
+ * Hands a committed row over. Awaited by the caller only on the legacy path — with an
68
+ * outbox this returns at once and the broker leaves the operation's path.
69
+ */
70
+ publish(row) {
71
+ // without a durable outbox this is the inline path, and the caller awaits the emission
72
+ if (!this.durable)
73
+ return this.#emission.emit(row.event);
74
+ /*
75
+ * A publication started while the pump is closing would outlive the emitters it needs,
76
+ * and `comq` waits on a connection that is going rather than failing. The row is already
77
+ * durable, so leaving it is exactly what it is for.
78
+ */
79
+ if (this.#closing ||
80
+ this.#defer ||
81
+ this.#inflight.size >= INFLIGHT ||
82
+ this.#published.size >= PUBLISHED)
83
+ return;
84
+ void this.#publish(row);
85
+ }
86
+ async open() {
87
+ if (!this.durable)
88
+ return;
89
+ if (this.#defer)
90
+ console.warn('Outbox immediate publication is deferred; events are published by the pump only');
91
+ this.#timer = setInterval(() => {
92
+ this.#tick();
93
+ }, this.#interval);
94
+ this.#timer.unref();
95
+ /*
96
+ * A lane changing hands is exactly when rows stranded in it become this replica's to
97
+ * publish, and the cycle would not notice for up to an interval. Being told costs a cycle
98
+ * that finds nothing in the usual case, where the claim arrives once and never changes.
99
+ */
100
+ this.#off = this.#atom.onassigned(() => {
101
+ this.#tick();
102
+ });
103
+ }
104
+ async close() {
105
+ this.#closing = true;
106
+ this.#off?.();
107
+ if (this.#timer !== undefined)
108
+ clearInterval(this.#timer);
109
+ await this.#drain();
110
+ await this.#mark();
111
+ }
112
+ /**
113
+ * Publishes one row and swallows the failure: the row stays unpublished and comes back on a
114
+ * later cycle, which is the whole point of having written it.
115
+ *
116
+ * There is no timeout here on purpose. A publication is a confirmed write to a durable
117
+ * exchange, and `comq` waits for the broker to come back rather than failing — abandoning
118
+ * it would not stop it, it would only mean the row is published twice once it lands. What
119
+ * bounds this instead is the in-flight cap and the drain on close.
120
+ *
121
+ */
122
+ async #publish(row) {
123
+ this.#publishing.add(row.id);
124
+ const publishing = this.#emission.emit(row.event);
125
+ this.#inflight.add(publishing);
126
+ try {
127
+ await publishing;
128
+ this.#published.add(row.id);
129
+ }
130
+ catch (error) {
131
+ console.warn('Event publication failed', { row: row.id, error });
132
+ }
133
+ finally {
134
+ this.#inflight.delete(publishing);
135
+ this.#publishing.delete(row.id);
136
+ }
137
+ }
138
+ /**
139
+ * `comq` retries a publish for as long as the broker is down rather than rejecting, so an
140
+ * unbounded drain outlives any grace period.
141
+ *
142
+ */
143
+ async #drain() {
144
+ if (this.#inflight.size === 0)
145
+ return;
146
+ await Promise.race([Promise.allSettled([...this.#inflight]), delay(DRAIN)]);
147
+ }
148
+ /**
149
+ * Reads what is due, publishes it, and marks everything this process has sent — what it just
150
+ * published and what the immediate path published since the last cycle. One cycle at a time.
151
+ *
152
+ */
153
+ #tick() {
154
+ if (this.#pumping)
155
+ return;
156
+ this.#pumping = true;
157
+ void this.#pump().finally(() => (this.#pumping = false));
158
+ }
159
+ async #pump() {
160
+ let page;
161
+ let after;
162
+ do {
163
+ page = await this.#read(after);
164
+ if (page.length === 0)
165
+ break;
166
+ // so a page is never read twice
167
+ after = page[page.length - 1]?.id;
168
+ /*
169
+ * A row is unpublished in the database until a cycle marks it, so a page includes what
170
+ * this replica is sending right now and what a failed marking left behind. Only this
171
+ * process knows either.
172
+ */
173
+ const rows = page.filter((row) => !this.#published.has(row.id) && !this.#publishing.has(row.id));
174
+ if (rows.length > 0) {
175
+ console.info('Outbox recovering unpublished events', { count: rows.length });
176
+ // every row is given its chance; what the broker refused stays unpublished and comes
177
+ // back on a later cycle
178
+ await Promise.allSettled(rows.map(async (row) => this.#publish(row)));
179
+ }
180
+ // a full page is a page that may have been cut short
181
+ } while (page.length === this.#batch);
182
+ await this.#mark();
183
+ }
184
+ /**
185
+ * One page of what is due. In a healthy system the first one is empty, every cycle — a row is
186
+ * due only if the process that wrote it failed to publish or died before marking it.
187
+ *
188
+ * Reading is suspended, not stopped, while this replica does not know which lanes are its
189
+ * own: the cycle keeps running and keeps marking, and reading resumes as soon as an
190
+ * assignment arrives. Reading without an assignment would be a different guarantee, where
191
+ * every replica publishes every stranded row.
192
+ *
193
+ * @param after the last id of the page before, so a page is never read twice
194
+ */
195
+ async #read(after) {
196
+ const lanes = this.#atom.slots(LANES);
197
+ if (lanes === null || lanes.length === 0)
198
+ return [];
199
+ return this.#storage
200
+ .outbox.pending(lanes, Date.now(), this.#batch, after)
201
+ .catch((error) => {
202
+ console.warn('Outbox read failed', { error });
203
+ return [];
204
+ });
205
+ }
206
+ /**
207
+ * One batched write for many events, which is why the ids are held in memory rather than
208
+ * marked one by one. Ids that fail to be marked are kept and retried; a row that is never
209
+ * marked is simply published again, which is within the contract.
210
+ *
211
+ */
212
+ async #mark() {
213
+ if (this.#published.size === 0)
214
+ return;
215
+ const ids = [...this.#published];
216
+ try {
217
+ await this.#storage.outbox.settle(ids);
218
+ for (const id of ids)
219
+ this.#published.delete(id);
220
+ }
221
+ catch (error) {
222
+ console.warn('Outbox marking failed', { count: ids.length, error });
223
+ }
224
+ }
225
+ /**
226
+ * A lane this replica currently owns, so that in steady state it settles its own rows
227
+ * before it ever reads them. Any lane at all when it owns none: the row still has to be
228
+ * written, and whoever ends up owning that lane will pump it.
229
+ *
230
+ */
231
+ #lane() {
232
+ const owned = this.#atom.slots(LANES);
233
+ return owned === null || owned.length === 0
234
+ ? Math.floor(Math.random() * LANES)
235
+ : owned[Math.floor(Math.random() * owned.length)];
236
+ }
237
+ }
238
+ function number(variable, declared, fallback) {
239
+ if (declared !== undefined)
240
+ return declared;
241
+ const value = Number(environment.get(variable));
242
+ return Number.isNaN(value) || value <= 0 ? fallback : value;
243
+ }
244
+ async function delay(ms) {
245
+ return new Promise((resolve) => {
246
+ setTimeout(resolve, ms).unref();
247
+ });
248
+ }
249
+ /**
250
+ * Constant, never configuration: rows carry their lane, so lowering this would leave rows in
251
+ * lanes nobody reads any more. It is also the ceiling on replicas of one component, and a
252
+ * power of two so that the common replica counts divide evenly.
253
+ */
254
+ export const LANES = 128;
255
+ /** one cycle reads, publishes and marks; in steady state it finds nothing to read */
256
+ const INTERVAL = 5000;
257
+ /**
258
+ * `gap = interval * K`. Not a steady-state necessity — a replica writes into a lane it owns
259
+ * and marks what it published — but a guard for when a lane changes hands between the write
260
+ * and the settle. Two cycles of separation, plus one of margin.
261
+ */
262
+ const K = 3;
263
+ /** how many rows one read brings back; the pump reads on while a page comes back full */
264
+ const BATCH = 200;
265
+ const DRAIN = 10_000;
266
+ const INFLIGHT = 1000;
267
+ const PUBLISHED = 10_000;
268
+ //# sourceMappingURL=outbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox.js","sourceRoot":"","sources":["../../source/outbox/outbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAa7C;;;;;;;;;;GAUG;AACH,MAAM,OAAO,MAAO,SAAQ,SAAS;IAC1B,SAAS,CAAU;IACnB,QAAQ,CAAqB;IAC7B,KAAK,CAAM;IAEX,IAAI,CAAQ;IACZ,SAAS,CAAQ;IACjB,MAAM,CAAQ;IACd,MAAM,CAAS;IAExB,oEAAoE;IAC3D,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;IAEvC,8DAA8D;IACrD,SAAS,GAAG,IAAI,GAAG,EAAiB,CAAA;IAE7C,wFAAwF;IAC/E,WAAW,GAAG,IAAI,GAAG,EAAU,CAAA;IAExC,MAAM,CAA4B;IAClC,IAAI,CAA0B;IAC9B,QAAQ,GAAG,KAAK,CAAA;IAChB,QAAQ,GAAG,KAAK,CAAA;IAEhB,sCAAsC;IACtC,YACE,QAAkB,EAClB,OAA4B,EAC5B,IAAU,EACV,OAAO,GAAY,EAAE;QAErB,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAA;QACzB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QAEjB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,qBAAqB,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC1E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,kBAAkB,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAC9D,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,SAAS,GAAG,CAAC,CAAA;QAC7C,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,kBAAkB,CAAC,KAAK,GAAG,CAAA;QAEzD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QACtB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAElB,IAAI,OAAO,KAAK,SAAS;YAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAClD,CAAC;IAED,sEAAsE;IACtE,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAA;IAC5C,CAAC;IAED;;;OAGG;IACI,GAAG,CAAC,KAAqB;QAC9B,OAAO;YACL,EAAE,EAAE,KAAK,EAAE;YACX,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;YAClB,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI;YAC/B,KAAK,EAAE,KAAc;SACtB,CAAA;IACH,CAAC;IAED;;;OAGG;IACI,OAAO,CAAC,GAAQ;QACrB,uFAAuF;QACvF,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAExD;;;;WAIG;QACH,IACE,IAAI,CAAC,QAAQ;YACb,IAAI,CAAC,MAAM;YACX,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,QAAQ;YAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,SAAS;YAEjC,OAAM;QAER,KAAK,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC;IAEkB,KAAK,CAAC,IAAI;QAC3B,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAM;QAEzB,IAAI,IAAI,CAAC,MAAM;YACb,OAAO,CAAC,IAAI,CACV,iFAAiF,CAClF,CAAA;QAEH,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;YAC7B,IAAI,CAAC,KAAK,EAAE,CAAA;QACd,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QAClB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;QAEnB;;;;WAIG;QACH,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE;YACrC,IAAI,CAAC,KAAK,EAAE,CAAA;QACd,CAAC,CAAC,CAAA;IACJ,CAAC;IAEkB,KAAK,CAAC,KAAK;QAC5B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QAEpB,IAAI,CAAC,IAAI,EAAE,EAAE,CAAA;QAEb,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAEzD,MAAM,IAAI,CAAC,MAAM,EAAE,CAAA;QACnB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,QAAQ,CAAC,GAAQ;QACrB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAE5B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAEjD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QAE9B,IAAI,CAAC;YACH,MAAM,UAAU,CAAA;YAEhB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,0BAA0B,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;QAClE,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;YACjC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM;QACV,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;YAAE,OAAM;QAErC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC7E,CAAC;IAED;;;;OAIG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAM;QAEzB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QAEpB,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAA;IAC1D,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAW,CAAA;QACf,IAAI,KAAyB,CAAA;QAE7B,GAAG,CAAC;YACF,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAE9B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAK;YAE5B,gCAAgC;YAChC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,CAAA;YAEjC;;;;eAIG;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CACtB,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CACvE,CAAA;YAED,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpB,OAAO,CAAC,IAAI,CAAC,sCAAsC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;gBAE5E,qFAAqF;gBACrF,wBAAwB;gBACxB,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;YACvE,CAAC;YAED,qDAAqD;QACvD,CAAC,QAAQ,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAC;QAErC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,KAAK,CAAC,KAAc;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAErC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAA;QAEnD,OAAO,IAAI,CAAC,QAAS;aAClB,MAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;aACtD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;YAE7C,OAAO,EAAE,CAAA;QACX,CAAC,CAAC,CAAA;IACN,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC;YAAE,OAAM;QAEtC,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAA;QAEhC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,QAAS,CAAC,MAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAExC,KAAK,MAAM,EAAE,IAAI,GAAG;gBAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;QACrE,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAErC,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YACzC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC;YACnC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;IACrD,CAAC;CACF;AAED,SAAS,MAAM,CACb,QAAgB,EAChB,QAA4B,EAC5B,QAAgB;IAEhB,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAA;IAE3C,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;IAE/C,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAA;AAC7D,CAAC;AAED,KAAK,UAAU,KAAK,CAAC,EAAU;IAC7B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAA;IACjC,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,GAAG,CAAA;AAExB,qFAAqF;AACrF,MAAM,QAAQ,GAAG,IAAI,CAAA;AAErB;;;;GAIG;AACH,MAAM,CAAC,GAAG,CAAC,CAAA;AAEX,yFAAyF;AACzF,MAAM,KAAK,GAAG,GAAG,CAAA;AAEjB,MAAM,KAAK,GAAG,MAAM,CAAA;AACpB,MAAM,QAAQ,GAAG,IAAI,CAAA;AACrB,MAAM,SAAS,GAAG,MAAM,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { Node } from '../types/storages.js';
2
+ /** What a component declares about the properties a criteria may select on. */
3
+ export type Properties = Record<string, {
4
+ type: string;
5
+ }>;
6
+ export declare function criteria(expression: string, properties?: Properties): Node;