@toa.io/core 1.0.0-alpha.31 → 1.0.0-alpha.310

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) 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 +165 -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 +148 -0
  16. package/transpiled/component.js.map +1 -0
  17. package/transpiled/composition.d.ts +6 -0
  18. package/transpiled/composition.js +20 -0
  19. package/transpiled/composition.js.map +1 -0
  20. package/transpiled/connector.d.ts +71 -0
  21. package/transpiled/connector.js +248 -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/component.d.ts +24 -0
  27. package/transpiled/contract/component.js +48 -0
  28. package/transpiled/contract/component.js.map +1 -0
  29. package/transpiled/contract/contract.d.ts +10 -0
  30. package/transpiled/contract/contract.js +14 -0
  31. package/transpiled/contract/contract.js.map +1 -0
  32. package/transpiled/contract/index.d.ts +3 -0
  33. package/transpiled/contract/index.js +4 -0
  34. package/transpiled/contract/index.js.map +1 -0
  35. package/transpiled/contract/reply.d.ts +7 -0
  36. package/transpiled/contract/reply.js +48 -0
  37. package/transpiled/contract/reply.js.map +1 -0
  38. package/transpiled/contract/request.d.ts +39 -0
  39. package/transpiled/contract/request.js +115 -0
  40. package/transpiled/contract/request.js.map +1 -0
  41. package/transpiled/contract/schemas.d.ts +4 -0
  42. package/transpiled/contract/schemas.js +36 -0
  43. package/transpiled/contract/schemas.js.map +1 -0
  44. package/transpiled/deliveries.d.ts +22 -0
  45. package/transpiled/deliveries.js +31 -0
  46. package/transpiled/deliveries.js.map +1 -0
  47. package/transpiled/effect.d.ts +7 -0
  48. package/transpiled/effect.js +13 -0
  49. package/transpiled/effect.js.map +1 -0
  50. package/transpiled/emission.d.ts +10 -0
  51. package/transpiled/emission.js +16 -0
  52. package/transpiled/emission.js.map +1 -0
  53. package/transpiled/encoded.d.ts +16 -0
  54. package/transpiled/encoded.js +25 -0
  55. package/transpiled/encoded.js.map +1 -0
  56. package/transpiled/entities/changeset.d.ts +10 -0
  57. package/transpiled/entities/changeset.js +27 -0
  58. package/transpiled/entities/changeset.js.map +1 -0
  59. package/transpiled/entities/entity.d.ts +19 -0
  60. package/transpiled/entities/entity.js +137 -0
  61. package/transpiled/entities/entity.js.map +1 -0
  62. package/transpiled/entities/factory.d.ts +27 -0
  63. package/transpiled/entities/factory.js +38 -0
  64. package/transpiled/entities/factory.js.map +1 -0
  65. package/transpiled/entities/index.d.ts +5 -0
  66. package/transpiled/entities/index.js +6 -0
  67. package/transpiled/entities/index.js.map +1 -0
  68. package/transpiled/entities/newid.d.ts +11 -0
  69. package/transpiled/entities/newid.js +41 -0
  70. package/transpiled/entities/newid.js.map +1 -0
  71. package/transpiled/entities/set.d.ts +10 -0
  72. package/transpiled/entities/set.js +19 -0
  73. package/transpiled/entities/set.js.map +1 -0
  74. package/transpiled/event.d.ts +14 -0
  75. package/transpiled/event.js +53 -0
  76. package/transpiled/event.js.map +1 -0
  77. package/transpiled/exceptions.d.ts +104 -0
  78. package/transpiled/exceptions.js +205 -0
  79. package/transpiled/exceptions.js.map +1 -0
  80. package/transpiled/gate.d.ts +40 -0
  81. package/transpiled/gate.js +84 -0
  82. package/transpiled/gate.js.map +1 -0
  83. package/transpiled/guard.d.ts +7 -0
  84. package/transpiled/guard.js +12 -0
  85. package/transpiled/guard.js.map +1 -0
  86. package/transpiled/halting.d.ts +16 -0
  87. package/transpiled/halting.js +25 -0
  88. package/transpiled/halting.js.map +1 -0
  89. package/transpiled/index.d.ts +41 -0
  90. package/transpiled/index.js +34 -0
  91. package/transpiled/index.js.map +1 -0
  92. package/transpiled/instance.d.ts +10 -0
  93. package/transpiled/instance.js +30 -0
  94. package/transpiled/instance.js.map +1 -0
  95. package/transpiled/locator.d.ts +12 -0
  96. package/transpiled/locator.js +32 -0
  97. package/transpiled/locator.js.map +1 -0
  98. package/transpiled/measurements.d.ts +20 -0
  99. package/transpiled/measurements.js +40 -0
  100. package/transpiled/measurements.js.map +1 -0
  101. package/transpiled/observation.d.ts +7 -0
  102. package/transpiled/observation.js +14 -0
  103. package/transpiled/observation.js.map +1 -0
  104. package/transpiled/operation.d.ts +69 -0
  105. package/transpiled/operation.js +174 -0
  106. package/transpiled/operation.js.map +1 -0
  107. package/transpiled/outbox.d.ts +45 -0
  108. package/transpiled/outbox.js +448 -0
  109. package/transpiled/outbox.js.map +1 -0
  110. package/transpiled/outbox.measurements.d.ts +4 -0
  111. package/transpiled/outbox.measurements.js +38 -0
  112. package/transpiled/outbox.measurements.js.map +1 -0
  113. package/transpiled/query/criteria.d.ts +6 -0
  114. package/transpiled/query/criteria.js +74 -0
  115. package/transpiled/query/criteria.js.map +1 -0
  116. package/transpiled/query/options.d.ts +3 -0
  117. package/transpiled/query/options.js +34 -0
  118. package/transpiled/query/options.js.map +1 -0
  119. package/transpiled/query.d.ts +9 -0
  120. package/transpiled/query.js +57 -0
  121. package/transpiled/query.js.map +1 -0
  122. package/transpiled/receiver.d.ts +20 -0
  123. package/transpiled/receiver.js +113 -0
  124. package/transpiled/receiver.js.map +1 -0
  125. package/transpiled/reflection.d.ts +9 -0
  126. package/transpiled/reflection.js +13 -0
  127. package/transpiled/reflection.js.map +1 -0
  128. package/transpiled/remote.d.ts +10 -0
  129. package/transpiled/remote.js +11 -0
  130. package/transpiled/remote.js.map +1 -0
  131. package/transpiled/safety.d.ts +5 -0
  132. package/transpiled/safety.js +26 -0
  133. package/transpiled/safety.js.map +1 -0
  134. package/transpiled/state.d.ts +36 -0
  135. package/transpiled/state.js +131 -0
  136. package/transpiled/state.js.map +1 -0
  137. package/transpiled/trail.d.ts +78 -0
  138. package/transpiled/trail.js +112 -0
  139. package/transpiled/trail.js.map +1 -0
  140. package/transpiled/transition.d.ts +14 -0
  141. package/transpiled/transition.js +51 -0
  142. package/transpiled/transition.js.map +1 -0
  143. package/transpiled/transmission.d.ts +8 -0
  144. package/transpiled/transmission.js +30 -0
  145. package/transpiled/transmission.js.map +1 -0
  146. package/transpiled/types/atomicity.d.ts +58 -0
  147. package/transpiled/types/atomicity.js +2 -0
  148. package/transpiled/types/atomicity.js.map +1 -0
  149. package/transpiled/types/bindings.d.ts +77 -0
  150. package/transpiled/types/bindings.js +2 -0
  151. package/transpiled/types/bindings.js.map +1 -0
  152. package/transpiled/types/bridges.d.ts +41 -0
  153. package/transpiled/types/bridges.js +2 -0
  154. package/transpiled/types/bridges.js.map +1 -0
  155. package/transpiled/types/extensions.d.ts +116 -0
  156. package/transpiled/types/extensions.js +2 -0
  157. package/transpiled/types/extensions.js.map +1 -0
  158. package/transpiled/types/inbox.d.ts +22 -0
  159. package/transpiled/types/inbox.js +2 -0
  160. package/transpiled/types/inbox.js.map +1 -0
  161. package/transpiled/types/index.d.ts +14 -0
  162. package/transpiled/types/index.js +9 -0
  163. package/transpiled/types/index.js.map +1 -0
  164. package/transpiled/types/message.d.ts +16 -0
  165. package/transpiled/types/message.js +2 -0
  166. package/transpiled/types/message.js.map +1 -0
  167. package/transpiled/types/operations.d.ts +15 -0
  168. package/transpiled/types/operations.js +2 -0
  169. package/transpiled/types/operations.js.map +1 -0
  170. package/transpiled/types/outbox.d.ts +54 -0
  171. package/transpiled/types/outbox.js +2 -0
  172. package/transpiled/types/outbox.js.map +1 -0
  173. package/transpiled/types/receiver.d.ts +9 -0
  174. package/transpiled/types/receiver.js +2 -0
  175. package/transpiled/types/receiver.js.map +1 -0
  176. package/transpiled/types/request.d.ts +119 -0
  177. package/transpiled/types/request.js +2 -0
  178. package/transpiled/types/request.js.map +1 -0
  179. package/transpiled/types/state.d.ts +9 -0
  180. package/transpiled/types/state.js +2 -0
  181. package/transpiled/types/state.js.map +1 -0
  182. package/transpiled/types/storages.d.ts +146 -0
  183. package/transpiled/types/storages.js +2 -0
  184. package/transpiled/types/storages.js.map +1 -0
  185. package/transpiled/unmanaged.d.ts +5 -0
  186. package/transpiled/unmanaged.js +7 -0
  187. package/transpiled/unmanaged.js.map +1 -0
  188. package/src/assignment.js +0 -31
  189. package/src/call.js +0 -42
  190. package/src/cascade.js +0 -35
  191. package/src/component.js +0 -41
  192. package/src/composition.js +0 -25
  193. package/src/connector.js +0 -183
  194. package/src/context.js +0 -55
  195. package/src/contract/conditions.js +0 -21
  196. package/src/contract/index.js +0 -7
  197. package/src/contract/reply.js +0 -25
  198. package/src/contract/request.js +0 -67
  199. package/src/contract/schemas/error.yaml +0 -9
  200. package/src/contract/schemas/index.js +0 -7
  201. package/src/contract/schemas/query.yaml +0 -30
  202. package/src/discovery.js +0 -44
  203. package/src/emission.js +0 -23
  204. package/src/entities/changeset.js +0 -38
  205. package/src/entities/entity.js +0 -74
  206. package/src/entities/factory.js +0 -33
  207. package/src/entities/index.js +0 -5
  208. package/src/entities/set.js +0 -15
  209. package/src/event.js +0 -40
  210. package/src/exceptions.js +0 -100
  211. package/src/exposition.js +0 -27
  212. package/src/index.js +0 -47
  213. package/src/locator.js +0 -54
  214. package/src/observation.js +0 -20
  215. package/src/operation.js +0 -69
  216. package/src/query/criteria.js +0 -41
  217. package/src/query/options.js +0 -40
  218. package/src/query.js +0 -41
  219. package/src/receiver.js +0 -61
  220. package/src/reflection.js +0 -28
  221. package/src/remote.js +0 -17
  222. package/src/state.js +0 -99
  223. package/src/transition.js +0 -67
  224. package/src/transmission.js +0 -33
  225. package/test/call.fixtures.js +0 -27
  226. package/test/call.test.js +0 -46
  227. package/test/component.fixtures.js +0 -21
  228. package/test/component.test.js +0 -40
  229. package/test/connector.fixtures.js +0 -40
  230. package/test/connector.test.js +0 -176
  231. package/test/context.fixtures.js +0 -18
  232. package/test/context.test.js +0 -29
  233. package/test/contract/conditions.test.js +0 -26
  234. package/test/contract/contract.fixtures.js +0 -33
  235. package/test/contract/request.test.js +0 -112
  236. package/test/emission.fixtures.js +0 -17
  237. package/test/emission.test.js +0 -35
  238. package/test/entities/entity.fixtures.js +0 -29
  239. package/test/entities/entity.test.js +0 -65
  240. package/test/entities/factory.fixtures.js +0 -18
  241. package/test/entities/factory.test.js +0 -48
  242. package/test/entities/set.fixtures.js +0 -11
  243. package/test/entities/set.test.js +0 -12
  244. package/test/event.fixtures.js +0 -29
  245. package/test/event.test.js +0 -118
  246. package/test/locator.test.js +0 -113
  247. package/test/query.fixtures.js +0 -100
  248. package/test/query.test.js +0 -86
  249. package/test/receiver.fixtures.js +0 -23
  250. package/test/receiver.test.js +0 -95
  251. package/test/reflection.test.js +0 -30
  252. package/test/state.fixtures.js +0 -47
  253. package/test/state.test.js +0 -46
  254. package/test/transmission.fixtures.js +0 -15
  255. package/test/transmission.test.js +0 -46
  256. package/types/bindings.d.ts +0 -40
  257. package/types/bridges.ts +0 -30
  258. package/types/component.d.ts +0 -9
  259. package/types/connector.d.ts +0 -18
  260. package/types/context.d.ts +0 -21
  261. package/types/entity.d.ts +0 -46
  262. package/types/event.d.ts +0 -11
  263. package/types/exception.d.ts +0 -4
  264. package/types/extensions.d.ts +0 -29
  265. package/types/index.ts +0 -14
  266. package/types/locator.d.ts +0 -13
  267. package/types/message.d.ts +0 -3
  268. package/types/operations.d.ts +0 -2
  269. package/types/query.d.ts +0 -15
  270. package/types/receiver.d.ts +0 -12
  271. package/types/reflection.d.ts +0 -14
  272. package/types/request.d.ts +0 -23
  273. package/types/state.d.ts +0 -35
  274. package/types/storages.d.ts +0 -71
@@ -0,0 +1,115 @@
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
+ // whether the call may reach only a safe operation, which every operation admits
42
+ readonly: { type: 'boolean' },
43
+ // what a caller receives of the output, which every operation admits
44
+ output: { type: 'array', uniqueItems: true, items: { type: 'string' } }
45
+ },
46
+ additionalProperties: true
47
+ };
48
+ const required = [];
49
+ if (definition.input !== undefined) {
50
+ schema.properties.input = definition.input;
51
+ required.push('input');
52
+ }
53
+ else
54
+ schema.properties.input = { type: 'null' };
55
+ if (entity === undefined)
56
+ definition.query = false;
57
+ if (definition.query === true)
58
+ required.push('query');
59
+ if (definition.query === false)
60
+ schema.properties.query = { type: 'null' };
61
+ if (definition.query !== false) {
62
+ const query = structuredClone(schemas.query);
63
+ query.properties.id = entity?.properties.id;
64
+ if (definition.type === 'observation')
65
+ delete query.properties.version;
66
+ else
67
+ delete query.properties.projection;
68
+ if (definition.type !== 'observation' || definition.scope !== 'objects') {
69
+ delete query.properties.omit;
70
+ delete query.properties.limit;
71
+ }
72
+ else if (query.required === undefined)
73
+ query.required = ['limit'];
74
+ else
75
+ query.required.push('limit');
76
+ schema.properties.query = query;
77
+ }
78
+ if (required.length > 0)
79
+ schema.required = required;
80
+ return schema;
81
+ }
82
+ }
83
+ /**
84
+ * What an operation of this type answers, where it did not say.
85
+ *
86
+ * A transition, an observation and an assignment work on the Entity Object, so that is what
87
+ * they answer — a set of them where the scope is a set. A computation neither uses the scope
88
+ * nor produces one, and an effect answers whatever it computed, so neither is guessed at.
89
+ * A stream is not a value with a schema, and is not one either.
90
+ *
91
+ * What the entity requires is said as well. It is a description and nothing is held to it —
92
+ * an operation answering a projection says so by declaring its own output — and a shape
93
+ * whose every property reads as optional says less than it knows.
94
+ */
95
+ function answers(definition, entity) {
96
+ if (entity === undefined || !ENTITY.has(definition.type))
97
+ return undefined;
98
+ const object = {
99
+ type: 'object',
100
+ properties: entity.properties,
101
+ ...(entity.required === undefined ? {} : { required: entity.required })
102
+ };
103
+ if (definition.scope === 'objects')
104
+ return { type: 'array', items: object };
105
+ return definition.scope === 'object' || definition.scope === 'changeset'
106
+ ? object
107
+ : undefined;
108
+ }
109
+ /** The types whose subject is the Entity Object; see `documentation/design.md`. */
110
+ const ENTITY = new Set(['transition', 'observation', 'assignment']);
111
+ /** A schema that states nothing, which is what an operation saying nothing normalizes to. */
112
+ function empty(schema) {
113
+ return schema === undefined || schema === null || Object.keys(schema).length === 0;
114
+ }
115
+ //# 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,22 @@
1
+ /**
2
+ * The messages this process has taken and not yet finished with.
3
+ *
4
+ * A binding counts one in for as long as it holds a delivery, and that is exactly what its own
5
+ * teardown waits for: a connection cannot close while a message it dispatched is still being
6
+ * handled, and a handler waiting on a call of its own holds it there. So this answers, for the
7
+ * process as a whole, whether a teardown has anything left to wait on.
8
+ *
9
+ * It is not `toa.call.inflight`, which counts the other side — callers waiting. That number is
10
+ * non-zero for a call a gateway made, which blocks no teardown, and zero for a handler held open
11
+ * by a database commit, which blocks one.
12
+ *
13
+ * Ambient, like the instance name and the invocation chain, and for the same reason: a process
14
+ * may carry two copies of this module, and a count kept in one of them answers for half a
15
+ * process.
16
+ */
17
+ /** One more delivery is being handled. */
18
+ export declare function taken(): void;
19
+ /** One fewer: the handler has returned, however it returned. */
20
+ export declare function done(): void;
21
+ /** How many this process is handling now. */
22
+ export declare function inflight(): number;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The messages this process has taken and not yet finished with.
3
+ *
4
+ * A binding counts one in for as long as it holds a delivery, and that is exactly what its own
5
+ * teardown waits for: a connection cannot close while a message it dispatched is still being
6
+ * handled, and a handler waiting on a call of its own holds it there. So this answers, for the
7
+ * process as a whole, whether a teardown has anything left to wait on.
8
+ *
9
+ * It is not `toa.call.inflight`, which counts the other side — callers waiting. That number is
10
+ * non-zero for a call a gateway made, which blocks no teardown, and zero for a handler held open
11
+ * by a database commit, which blocks one.
12
+ *
13
+ * Ambient, like the instance name and the invocation chain, and for the same reason: a process
14
+ * may carry two copies of this module, and a count kept in one of them answers for half a
15
+ * process.
16
+ */
17
+ const KEY = Symbol.for('toa.core.deliveries');
18
+ const store = (globalThis[KEY] ??= { count: 0 });
19
+ /** One more delivery is being handled. */
20
+ export function taken() {
21
+ store.count++;
22
+ }
23
+ /** One fewer: the handler has returned, however it returned. */
24
+ export function done() {
25
+ store.count--;
26
+ }
27
+ /** How many this process is handling now. */
28
+ export function inflight() {
29
+ return store.count;
30
+ }
31
+ //# sourceMappingURL=deliveries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deliveries.js","sourceRoot":"","sources":["../source/deliveries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAA;AAI7C,MAAM,KAAK,GAAG,CAAE,UAAoB,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;AAE3D,0CAA0C;AAC1C,MAAM,UAAU,KAAK;IACnB,KAAK,CAAC,KAAK,EAAE,CAAA;AACf,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,IAAI;IAClB,KAAK,CAAC,KAAK,EAAE,CAAA;AACf,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,QAAQ;IACtB,OAAO,KAAK,CAAC,KAAK,CAAA;AACpB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { Observation } from './observation.ts';
2
+ import type { Store } from './operation.ts';
3
+ export declare class Effect extends Observation {
4
+ /** an effect reads for what it does next, which a projected read would leave short */
5
+ protected projects: boolean;
6
+ protected acquire(store: Store): Promise<void>;
7
+ }
@@ -0,0 +1,13 @@
1
+ import { Observation } from './observation.js';
2
+ export class Effect extends Observation {
3
+ /** an effect reads for what it does next, which a projected read would leave short */
4
+ projects = false;
5
+ async acquire(store) {
6
+ const { query, entity, input } = store.request;
7
+ if (entity === undefined)
8
+ return super.acquire(store);
9
+ store.scope = await this.scope.ensure(query, entity, input);
10
+ store.state = store.scope.get();
11
+ }
12
+ }
13
+ //# 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;IACrC,sFAAsF;IACnE,QAAQ,GAAY,KAAK,CAAA;IAEzB,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,10 @@
1
+ import { Connector } from './connector.ts';
2
+ import type { Event } from './event.ts';
3
+ import type { Row } from './types/outbox.ts';
4
+ export declare class Emission extends Connector {
5
+ #private;
6
+ /** what a row is outstanding for while this has not published it */
7
+ readonly name = "events";
8
+ constructor(events: Event[]);
9
+ emit(row: Row): Promise<void>;
10
+ }
@@ -0,0 +1,16 @@
1
+ import { Connector } from './connector.js';
2
+ export class Emission extends Connector {
3
+ /** what a row is outstanding for while this has not published it */
4
+ name = 'events';
5
+ #events;
6
+ constructor(events) {
7
+ super();
8
+ this.#events = events;
9
+ this.depends(events);
10
+ }
11
+ async emit(row) {
12
+ const emission = this.#events.map((e) => e.emit(row));
13
+ await Promise.all(emission);
14
+ }
15
+ }
16
+ //# 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;IACrC,oEAAoE;IACpD,IAAI,GAAG,QAAQ,CAAA;IAEtB,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,GAAQ;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QAErD,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC7B,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * An output a component encoded, which its caller passes on as it is: the bytes of what the
3
+ * operation answered, and what they are encoded in. A caller that writes them somewhere — the
4
+ * gateway writing a response body — spends nothing on reading them.
5
+ */
6
+ export declare class Encoded {
7
+ readonly bytes: Buffer;
8
+ readonly type: string;
9
+ constructor(bytes: Buffer, type?: string);
10
+ /**
11
+ * Whether a value is an `Encoded`, whichever copy of this package made it. A process may load
12
+ * the package more than once — the gateway image installs it beside the runtime and again beside
13
+ * the extension — and what one copy made is no instance of the other copy's class.
14
+ */
15
+ static is(value: unknown): value is Encoded;
16
+ }
@@ -0,0 +1,25 @@
1
+ /** What marks an `Encoded` in every copy of this package, which its class does not: see `is`. */
2
+ const KEY = Symbol.for('toa.core.encoded');
3
+ /**
4
+ * An output a component encoded, which its caller passes on as it is: the bytes of what the
5
+ * operation answered, and what they are encoded in. A caller that writes them somewhere — the
6
+ * gateway writing a response body — spends nothing on reading them.
7
+ */
8
+ export class Encoded {
9
+ bytes;
10
+ type;
11
+ constructor(bytes, type = 'application/json') {
12
+ this.bytes = bytes;
13
+ this.type = type;
14
+ Object.defineProperty(this, KEY, { value: true });
15
+ }
16
+ /**
17
+ * Whether a value is an `Encoded`, whichever copy of this package made it. A process may load
18
+ * the package more than once — the gateway image installs it beside the runtime and again beside
19
+ * the extension — and what one copy made is no instance of the other copy's class.
20
+ */
21
+ static is(value) {
22
+ return typeof value === 'object' && value !== null && KEY in value;
23
+ }
24
+ }
25
+ //# sourceMappingURL=encoded.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoded.js","sourceRoot":"","sources":["../source/encoded.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;AAE1C;;;;GAIG;AACH,MAAM,OAAO,OAAO;IACF,KAAK,CAAQ;IACb,IAAI,CAAQ;IAE5B,YAAmB,KAAa,EAAE,IAAI,GAAW,kBAAkB;QACjE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAEhB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACnD,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,EAAE,CAAC,KAAc;QAC7B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,CAAA;IACpE,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import type { Schema } from '@toa.io/schemas';
2
+ import type { Query, Record } from '../types/storages.ts';
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.ts';
3
+ import type { Record } from '../types/storages.ts';
4
+ import type { Event } from '../types/state.ts';
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
+ }
@@ -0,0 +1,137 @@
1
+ import { environment } from '@toa.io/generic';
2
+ import { EntityContractException, EntityGuardException } from '../exceptions.js';
3
+ import { newid } from './newid.js';
4
+ export class Entity {
5
+ deleted = false;
6
+ #schema;
7
+ #blank;
8
+ #guards;
9
+ #origin = null;
10
+ #state;
11
+ #mutable = true;
12
+ /**
13
+ * A record makes an entity of what a storage holds; a string, or nothing at all, makes a
14
+ * blank one under that identity, out of what the component declared a record starts as.
15
+ *
16
+ * @param blank what the component declares a record holds before anything is written to it
17
+ * @param mutable whether the entity may be modified and committed
18
+ */
19
+ // eslint-disable-next-line max-params
20
+ constructor(schema, blank, argument, guards, mutable = true) {
21
+ this.#schema = schema;
22
+ this.#blank = blank;
23
+ this.#guards = guards;
24
+ if (typeof argument === 'object')
25
+ this.#acquire(argument, mutable);
26
+ else
27
+ this.#write(this.#compose(argument ?? newid()));
28
+ }
29
+ get() {
30
+ return this.#state;
31
+ }
32
+ set(value) {
33
+ if (!this.#mutable)
34
+ throw new Error('Entity acquired by a read-only operation cannot be modified');
35
+ this.#guard(value);
36
+ const error = this.#schema.fit(value);
37
+ if (error !== null)
38
+ throw new EntityContractException(error, value);
39
+ this.#revive(value);
40
+ this.#write(value);
41
+ }
42
+ event(input) {
43
+ return {
44
+ origin: this.#origin,
45
+ state: this.#state,
46
+ trailers: this.#state._trailers,
47
+ input
48
+ };
49
+ }
50
+ /**
51
+ * The origin is the pre-image a commit diffs the new state against. An operation that
52
+ * cannot commit has nothing to diff, so it takes the record as it came from the storage
53
+ * instead of paying for a deep copy of every record it read.
54
+ */
55
+ #acquire(record, mutable) {
56
+ this.#mutable = mutable;
57
+ if (!mutable) {
58
+ this.#write(record);
59
+ return;
60
+ }
61
+ this.#write(structuredClone(record));
62
+ this.#origin = record;
63
+ }
64
+ /**
65
+ * A blank is not validated: what the component declared is fitted once, at boot, and the
66
+ * system properties are the runtime's own. It is copied because every entity the component
67
+ * makes is written over its own.
68
+ */
69
+ #compose(id) {
70
+ // `REGION` here as well as in `#write`, because a record is validated before it is written
71
+ // and what is composed is about to be written here: it is this region's
72
+ return {
73
+ id,
74
+ VERSION: 0,
75
+ DELETED: null,
76
+ REGION,
77
+ ...structuredClone(this.#blank)
78
+ };
79
+ }
80
+ #guard(value) {
81
+ if (this.#guards === undefined)
82
+ return;
83
+ for (const guard of this.#guards) {
84
+ const ok = guard.fit(value, this.#origin);
85
+ if (ok === false)
86
+ throw new EntityGuardException(guard.name, value);
87
+ }
88
+ }
89
+ // deletion is only expressed as a new DELETED timestamp,
90
+ // so committing over a tombstone without touching it means revival
91
+ #revive(value) {
92
+ if (this.#origin?.DELETED == null || value.DELETED !== this.#origin.DELETED)
93
+ return;
94
+ value.DELETED = null;
95
+ this.deleted = false;
96
+ }
97
+ #write(value) {
98
+ if (!('_trailers' in value))
99
+ Object.defineProperty(value, '_trailers', {
100
+ writable: false,
101
+ configurable: false,
102
+ enumerable: false,
103
+ value: {}
104
+ });
105
+ /*
106
+ * The system properties are the runtime's to write, and a record does not always come from
107
+ * a storage that wrote them: a component may bring its own, and one that answers with an
108
+ * id and a version has left the rest to whoever asked. Filling them in here is what makes
109
+ * a record's shape the runtime's guarantee rather than a storage's promise, and what lets
110
+ * the entity require them.
111
+ */
112
+ value.CREATED ??= Date.now();
113
+ value.UPDATED ??= value.CREATED;
114
+ value.VERSION ??= 0;
115
+ value.DELETED ??= null;
116
+ value.REGION ??= REGION;
117
+ if (value.DELETED !== null)
118
+ this.deleted = true;
119
+ // beside the version and the timestamp, and for the same reason: all three say what the
120
+ // write did, so all three change only where there is one. A record read here keeps the
121
+ // region that wrote it, which is not necessarily this one — that is the whole of what it
122
+ // is for, and stamping it on the way in would answer every read with the wrong region.
123
+ if (this.#state !== undefined) {
124
+ value.UPDATED = Date.now();
125
+ value.VERSION++;
126
+ value.REGION = REGION;
127
+ }
128
+ this.#state = value;
129
+ }
130
+ }
131
+ /**
132
+ * The rank of the region this deployment is, from what deployed it. An application that is one
133
+ * region has none and writes `0`, which is what the first region is and what a record written
134
+ * before any of this existed is backfilled with.
135
+ */
136
+ const REGION = Number(environment.get('TOA_REGION') ?? 0);
137
+ //# sourceMappingURL=entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity.js","sourceRoot":"","sources":["../../source/entities/entity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { Entity } from './entity.ts';
2
+ import { EntitySet } from './set.ts';
3
+ import { Changeset } from './changeset.ts';
4
+ import type { Schema } from '@toa.io/schemas';
5
+ import type { Guard } from '../guard.ts';
6
+ import type { Query, Record } from '../types/storages.ts';
7
+ /** The two schemas a component's records are held to, and what a new one starts as. */
8
+ export interface Schemas {
9
+ /** what a stored record must fit */
10
+ entity: Schema;
11
+ /** what a changeset must fit: the same properties, none of them required */
12
+ changeset: Schema;
13
+ }
14
+ export declare class Factory {
15
+ #private;
16
+ constructor(schemas: Schemas, blank: object, guards?: Guard[]);
17
+ /**
18
+ * What these values would make of a record, held to what a record must be. It starts from a
19
+ * blank rather than from the declared properties alone, because what is validated is the
20
+ * record and a record carries what the runtime writes into every one of them.
21
+ */
22
+ fit(values: object): void;
23
+ init(id?: string): Entity;
24
+ object(record: Record, mutable?: boolean): Entity;
25
+ objects(recordset: Record[], init?: string[], mutable?: boolean): EntitySet;
26
+ changeset(query: Query): Changeset;
27
+ }
@@ -0,0 +1,38 @@
1
+ import { Entity } from './entity.js';
2
+ import { EntitySet } from './set.js';
3
+ import { Changeset } from './changeset.js';
4
+ export class Factory {
5
+ #schemas;
6
+ #blank;
7
+ #guards;
8
+ constructor(schemas, blank, guards) {
9
+ this.#schemas = schemas;
10
+ this.#blank = blank;
11
+ this.#guards = guards;
12
+ }
13
+ /**
14
+ * What these values would make of a record, held to what a record must be. It starts from a
15
+ * blank rather than from the declared properties alone, because what is validated is the
16
+ * record and a record carries what the runtime writes into every one of them.
17
+ */
18
+ fit(values) {
19
+ this.#schemas.entity.validate({ ...this.init().get(), ...values }, 'Entity');
20
+ }
21
+ init(id) {
22
+ return new Entity(this.#schemas.entity, this.#blank, id, this.#guards);
23
+ }
24
+ object(record, mutable = true) {
25
+ return new Entity(this.#schemas.entity, this.#blank, record, this.#guards, mutable);
26
+ }
27
+ objects(recordset, init, mutable = true) {
28
+ const set = recordset.map((record) => this.object(record, mutable));
29
+ if (init !== undefined)
30
+ for (const id of init)
31
+ set.unshift(this.init(id));
32
+ return new EntitySet(set);
33
+ }
34
+ changeset(query) {
35
+ return new Changeset(this.#schemas.changeset, query);
36
+ }
37
+ }
38
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../source/entities/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAc1C,MAAM,OAAO,OAAO;IACT,QAAQ,CAAS;IACjB,MAAM,CAAQ;IACd,OAAO,CAAqB;IAErC,YAAmB,OAAgB,EAAE,KAAa,EAAE,MAAgB;QAClE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;QACnB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;IACvB,CAAC;IAED;;;;OAIG;IACI,GAAG,CAAC,MAAc;QACvB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,QAAQ,CAAC,CAAA;IAC9E,CAAC;IAEM,IAAI,CAAC,EAAW;QACrB,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IACxE,CAAC;IAEM,MAAM,CAAC,MAAc,EAAE,OAAO,GAAG,IAAI;QAC1C,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACrF,CAAC;IAEM,OAAO,CAAC,SAAmB,EAAE,IAAe,EAAE,OAAO,GAAG,IAAI;QACjE,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;QAEnE,IAAI,IAAI,KAAK,SAAS;YAAE,KAAK,MAAM,EAAE,IAAI,IAAI;gBAAE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;QAEzE,OAAO,IAAI,SAAS,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC;IAEM,SAAS,CAAC,KAAY;QAC3B,OAAO,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;IACtD,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ export { derive, newid } from './newid.ts';
2
+ export { Factory } from './factory.ts';
3
+ export { Entity } from './entity.ts';
4
+ export { EntitySet } from './set.ts';
5
+ export { Changeset } from './changeset.ts';
@@ -0,0 +1,6 @@
1
+ export { derive, newid } from './newid.js';
2
+ export { Factory } from './factory.js';
3
+ export { Entity } from './entity.js';
4
+ export { EntitySet } from './set.js';
5
+ export { Changeset } from './changeset.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/entities/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA"}