@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
@@ -1,10 +1,10 @@
1
- import { describe, it, beforeEach, mock } from 'node:test'
1
+ import { describe, it, beforeEach } from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
3
 
4
4
  import * as fixtures from './context.fixtures.js'
5
- import { Context } from '../src/context.js'
5
+ import { Context } from '../source/context.js'
6
6
 
7
- /** @type {toa.core.Context} */
7
+ /** @type {import('@toa.io/core').Context} */
8
8
  let context
9
9
 
10
10
  beforeEach(() => {
@@ -29,7 +29,7 @@ describe('call', () => {
29
29
  })
30
30
  })
31
31
 
32
- function resetCalls (target = [assert, fixtures], seen = new Set()) {
32
+ function resetCalls(target = [assert, fixtures], seen = new Set()) {
33
33
  if (target === null || typeof target !== 'object' || seen.has(target)) return
34
34
 
35
35
  seen.add(target)
@@ -4,7 +4,7 @@ import { isDeepStrictEqual } from 'node:util'
4
4
 
5
5
  import { generate } from 'randomstring'
6
6
 
7
- import { Contract } from '../../src/contract/contract.js'
7
+ import { Contract } from '../../source/contract/contract.js'
8
8
  import * as fixtures from './contract.fixtures.js'
9
9
 
10
10
  let contract
@@ -18,7 +18,11 @@ it('should fit value', () => {
18
18
 
19
19
  contract.fit(value)
20
20
 
21
- assert.ok(fixtures.schema.fit.mock.calls.some((call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], value)))
21
+ assert.ok(
22
+ fixtures.schema.fit.mock.calls.some(
23
+ (call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], value)
24
+ )
25
+ )
22
26
  })
23
27
 
24
28
  it('should throw on invalid value', () => {
@@ -1,9 +1,8 @@
1
1
  import { mock } from 'node:test'
2
2
 
3
3
  import { generate } from 'randomstring'
4
- import { readFileSync } from 'node:fs'
5
- import { load as parseYAML } from 'js-yaml'
6
- import { resolve } from 'path'
4
+
5
+ import { query as querySchema } from '../../source/contract/schemas.js'
7
6
 
8
7
  // noinspection JSCheckFunctionSignatures
9
8
  export const schema = {
@@ -21,7 +20,7 @@ export const schemas = {
21
20
  type: 'object',
22
21
  properties: {
23
22
  input: { type: 'null' },
24
- query: parseYAML(readFileSync(resolve(import.meta.dirname, '../../src/contract/schemas/query.yaml'), 'utf8')),
23
+ query: querySchema,
25
24
  authentic: { type: 'boolean' }
26
25
  },
27
26
  additionalProperties: true
@@ -6,8 +6,8 @@ import { isDeepStrictEqual } from 'node:util'
6
6
  import clone from 'clone-deep'
7
7
  import { generate } from 'randomstring'
8
8
 
9
- import { Request } from '../../src/contract/request.js'
10
- import { Contract } from '../../src/contract/contract.js'
9
+ import { Request } from '../../source/contract/request.js'
10
+ import { Contract } from '../../source/contract/contract.js'
11
11
  import * as fixtures from './contract.fixtures.js'
12
12
 
13
13
  // the base is real; what it was constructed with and told to fit is observable
@@ -22,7 +22,7 @@ beforeEach(() => {
22
22
  contract = new Request(fixtures.schema, {})
23
23
  })
24
24
 
25
- const dummy = { schema: { properties: {} } }
25
+ const dummy = { properties: {} }
26
26
 
27
27
  it('should extend Conditions', () => {
28
28
  assert.ok(contract instanceof Contract)
@@ -34,8 +34,11 @@ it('should fit request', () => {
34
34
 
35
35
  contract.fit(request)
36
36
 
37
- assert.ok(fit.mock.calls.some((call) =>
38
- call.this === contract && isDeepStrictEqual(call.arguments[0], request)))
37
+ assert.ok(
38
+ fit.mock.calls.some(
39
+ (call) => call.this === contract && isDeepStrictEqual(call.arguments[0], request)
40
+ )
41
+ )
39
42
  })
40
43
 
41
44
  describe('schema', () => {
@@ -70,21 +73,45 @@ describe('schema', () => {
70
73
 
71
74
  it('should require query if declaration.query is true', () => {
72
75
  schema.required = ['query']
73
- assert.ok(['query'].every((item) => Request.schema({ query: true }, dummy).required.some((candidate) => isDeepStrictEqual(candidate, item))))
76
+ assert.ok(
77
+ ['query'].every((item) =>
78
+ Request.schema({ query: true }, dummy).required.some((candidate) =>
79
+ isDeepStrictEqual(candidate, item)
80
+ )
81
+ )
82
+ )
74
83
  })
75
84
 
76
85
  it('should forbid projection for non observations', () => {
77
- assert.strictEqual(Request.schema({ type: 'transition' }, dummy).properties.query.properties.projection, undefined)
78
-
79
- assert.strictEqual(Request.schema({ type: 'assignment' }, dummy).properties.query.properties.projection, undefined)
80
-
81
- assert.notStrictEqual(Request.schema({ type: 'observation' }, dummy).properties.query.properties.projection, undefined)
86
+ assert.strictEqual(
87
+ Request.schema({ type: 'transition' }, dummy).properties.query.properties
88
+ .projection,
89
+ undefined
90
+ )
91
+
92
+ assert.strictEqual(
93
+ Request.schema({ type: 'assignment' }, dummy).properties.query.properties
94
+ .projection,
95
+ undefined
96
+ )
97
+
98
+ assert.notStrictEqual(
99
+ Request.schema({ type: 'observation' }, dummy).properties.query.properties
100
+ .projection,
101
+ undefined
102
+ )
82
103
  })
83
104
 
84
105
  it('should forbid version for observations', () => {
85
- assert.notStrictEqual(Request.schema({ type: 'transition' }, dummy).properties.query.properties.version, undefined)
86
-
87
- assert.strictEqual(Request.schema({ type: 'observation' }, dummy).properties.query.properties.version, undefined)
106
+ assert.notStrictEqual(
107
+ Request.schema({ type: 'transition' }, dummy).properties.query.properties.version,
108
+ undefined
109
+ )
110
+
111
+ assert.strictEqual(
112
+ Request.schema({ type: 'observation' }, dummy).properties.query.properties.version,
113
+ undefined
114
+ )
88
115
  })
89
116
 
90
117
  it('should allow omit, limit only for set observations', () => {
@@ -94,18 +121,24 @@ describe('schema', () => {
94
121
  assert.strictEqual(transition.omit, undefined)
95
122
  assert.strictEqual(transition.limit, undefined)
96
123
 
97
- const object = Request.schema({
98
- type: 'observation',
99
- scope: 'object'
100
- }, dummy).properties.query.properties
124
+ const object = Request.schema(
125
+ {
126
+ type: 'observation',
127
+ scope: 'object'
128
+ },
129
+ dummy
130
+ ).properties.query.properties
101
131
 
102
132
  assert.strictEqual(object.omit, undefined)
103
133
  assert.strictEqual(object.limit, undefined)
104
134
 
105
- const objects = Request.schema({
106
- type: 'observation',
107
- scope: 'objects'
108
- }, dummy).properties.query.properties
135
+ const objects = Request.schema(
136
+ {
137
+ type: 'observation',
138
+ scope: 'objects'
139
+ },
140
+ dummy
141
+ ).properties.query.properties
109
142
 
110
143
  assert.notStrictEqual(objects.omit, undefined)
111
144
  assert.notStrictEqual(objects.limit, undefined)
@@ -113,16 +146,13 @@ describe('schema', () => {
113
146
  })
114
147
 
115
148
  describe('source', () => {
116
-
117
-
118
149
  const compile = (definition, entity) =>
119
- schemas.schema(Request.schema(definition, entity), { removeAdditional: true })
150
+ schemas.schema(Request.schema(definition, entity))
120
151
 
121
- it('should declare source', () => {
152
+ it('should not hold source to a schema', () => {
122
153
  const schema = Request.schema({}, dummy)
123
154
 
124
- assert.notStrictEqual(schema.properties.source, undefined)
125
- assert.deepStrictEqual(schema.properties.source.additionalProperties, false)
155
+ assert.strictEqual(schema.properties.source, undefined)
126
156
  })
127
157
 
128
158
  it('should pass known source variants', () => {
@@ -140,18 +170,22 @@ describe('source', () => {
140
170
  }
141
171
  })
142
172
 
143
- // `source` crosses the wire and keys the introspection map, so whatever
144
- // a peer adds to it must not survive
145
- it('should strip unknown source properties', () => {
173
+ // whatever a peer puts beside the keys this release knows travels through: what reads
174
+ // `source` takes the keys it knows, and the contract does not fail a call over the rest
175
+ it('should pass a source a peer added to', () => {
146
176
  const schema = compile({}, undefined)
147
- const request = { input: null, query: null, source: { service: 'exposition', evil: 'x' } }
177
+ const request = {
178
+ input: null,
179
+ query: null,
180
+ source: { service: 'exposition', mystery: 'x' }
181
+ }
148
182
 
149
183
  assert.deepStrictEqual(schema.fit(request), null)
150
- assert.deepStrictEqual(request.source, { service: 'exposition' })
184
+ assert.deepStrictEqual(request.source, { service: 'exposition', mystery: 'x' })
151
185
  })
152
186
  })
153
187
 
154
- function resetCalls (target = [assert, clone, fixtures, dummy], seen = new Set()) {
188
+ function resetCalls(target = [assert, clone, fixtures, dummy], seen = new Set()) {
155
189
  if (target === null || typeof target !== 'object' || seen.has(target)) return
156
190
 
157
191
  seen.add(target)
@@ -3,8 +3,8 @@ import assert from 'node:assert/strict'
3
3
  import { isDeepStrictEqual } from 'node:util'
4
4
 
5
5
  import { console } from 'openspan'
6
- import { Connector } from '../src/connector.js'
7
- import { Discovery } from '../src/discovery.js'
6
+ import { Connector } from '../source/connector.js'
7
+ import { Discovery } from '../source/discovery.js'
8
8
 
9
9
  class Lookup extends Connector {
10
10
  invoke = mock.fn(async () => ({ operations: {} }))
@@ -60,5 +60,12 @@ it('should keep warning while a lookup is unanswered', async () => {
60
60
 
61
61
  assert.strictEqual(warn.mock.callCount(), 2)
62
62
 
63
- assert.ok(((call) => call.arguments.length === 2 && isDeepStrictEqual(call.arguments[0], 'Waiting for lookup response') && isDeepStrictEqual(call.arguments[1], { component: locator.id, waiting: 10 }))(warn.mock.calls.at(-1) ?? { arguments: [] }))
63
+ assert.ok(
64
+ ((call) =>
65
+ call.arguments.length === 2 &&
66
+ isDeepStrictEqual(call.arguments[0], 'Waiting for lookup response') &&
67
+ isDeepStrictEqual(call.arguments[1], { component: locator.id, waiting: 10 }))(
68
+ warn.mock.calls.at(-1) ?? { arguments: [] }
69
+ )
70
+ )
64
71
  })
@@ -4,15 +4,16 @@ import { isDeepStrictEqual } from 'node:util'
4
4
 
5
5
  import clone from 'clone-deep'
6
6
 
7
- import { Connector } from '../src/connector.js'
7
+ import { Connector } from '../source/connector.js'
8
8
 
9
9
  // the fixtures are not connectors, so a dependency is recorded rather than linked
10
10
  const depends = mock.method(Connector.prototype, 'depends', () => undefined)
11
11
 
12
- const dependencies = (instance) => depends.mock.calls
13
- .filter((call) => call.this === instance)
14
- .map((call) => call.arguments[0])
15
- import { Emission } from '../src/emission.js'
12
+ const dependencies = (instance) =>
13
+ depends.mock.calls
14
+ .filter((call) => call.this === instance)
15
+ .map((call) => call.arguments[0])
16
+ import { Emission } from '../source/emission.js'
16
17
  import * as fixtures from './emission.fixtures.js'
17
18
 
18
19
  let emission, event
@@ -33,15 +34,22 @@ it('should depend on events', () => {
33
34
  })
34
35
 
35
36
  it('should emit events', async () => {
36
-
37
37
  await emission.emit(event)
38
38
 
39
39
  for (const evt of fixtures.events) {
40
- assert.ok(evt.emit.mock.calls.some((call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], event)))
40
+ assert.ok(
41
+ evt.emit.mock.calls.some(
42
+ (call) =>
43
+ call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], event)
44
+ )
45
+ )
41
46
  }
42
47
  })
43
48
 
44
- function resetCalls (target = [assert, clone, depends, dependencies, fixtures], seen = new Set()) {
49
+ function resetCalls(
50
+ target = [assert, clone, depends, dependencies, fixtures],
51
+ seen = new Set()
52
+ ) {
45
53
  if (target === null || typeof target !== 'object' || seen.has(target)) return
46
54
 
47
55
  seen.add(target)
@@ -4,8 +4,7 @@ import { generate } from 'randomstring'
4
4
 
5
5
  // noinspection JSCheckFunctionSignatures
6
6
  export const schema = {
7
- fit: mock.fn((object) =>
8
- (object.fail ? { [generate()]: generate() } : null)),
7
+ fit: mock.fn((object) => (object.fail ? { [generate()]: generate() } : null)),
9
8
 
10
9
  defaults: mock.fn(() => ({ [generate()]: generate() }))
11
10
  }
@@ -13,10 +12,10 @@ export const schema = {
13
12
  export const state = () => ({
14
13
  id: generate(),
15
14
  foo: generate(),
16
- _created: generate(),
17
- _updated: generate(),
18
- _deleted: generate(),
19
- _version: 0
15
+ CREATED: generate(),
16
+ UPDATED: generate(),
17
+ DELETED: generate(),
18
+ VERSION: 0
20
19
  })
21
20
 
22
21
  export const failed = () => ({
@@ -1,9 +1,11 @@
1
- import { describe, it, beforeEach, mock } from 'node:test'
1
+ import { describe, it, beforeEach } from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
3
 
4
- import { Entity } from '../../src/entities/entity.js'
4
+ import { Entity } from '../../source/entities/entity.js'
5
5
  import * as fixtures from './entity.fixtures.js'
6
6
 
7
+ const BLANK = {}
8
+
7
9
  beforeEach(() => {
8
10
  resetCalls()
9
11
  })
@@ -11,74 +13,106 @@ beforeEach(() => {
11
13
  describe('argument', () => {
12
14
  it('should set state', () => {
13
15
  const state = fixtures.state()
14
- const entity = new Entity(fixtures.schema, state)
16
+ const entity = new Entity(fixtures.schema, BLANK, state)
15
17
 
16
18
  assert.deepStrictEqual(entity.get(), state)
17
19
  })
18
20
 
19
21
  it('should snapshot the record it may commit', () => {
20
22
  const record = fixtures.state()
21
- const entity = new Entity(fixtures.schema, record)
23
+ const entity = new Entity(fixtures.schema, BLANK, record)
22
24
 
23
25
  assert.notStrictEqual(entity.get(), record)
24
26
  assert.strictEqual(entity.event().origin, record)
25
27
  })
26
28
  })
27
29
 
30
+ describe('blank', () => {
31
+ it('should write what the component declares a record starts as', () => {
32
+ const entity = new Entity(fixtures.schema, { foo: 'declared' })
33
+ const state = entity.get()
34
+
35
+ assert.strictEqual(state.foo, 'declared')
36
+ assert.strictEqual(state.VERSION, 0)
37
+ assert.strictEqual(state.DELETED, null)
38
+ assert.strictEqual(typeof state.id, 'string')
39
+ assert.strictEqual(entity.event().origin, null)
40
+ })
41
+
42
+ it('should not validate it', () => {
43
+ const entity = new Entity(fixtures.schema, { fail: true })
44
+
45
+ assert.strictEqual(entity.get().fail, true)
46
+ assert.strictEqual(fixtures.schema.fit.mock.callCount(), 0)
47
+ })
48
+
49
+ it('should give every record its own copy', () => {
50
+ const blank = { foo: { bar: 'nested' } }
51
+ const one = new Entity(fixtures.schema, blank)
52
+ const other = new Entity(fixtures.schema, blank)
53
+
54
+ assert.notStrictEqual(one.get().foo, other.get().foo)
55
+ assert.notStrictEqual(one.get().foo, blank.foo)
56
+ })
57
+ })
58
+
28
59
  describe('read-only', () => {
29
60
  it('should take the record as it came', () => {
30
61
  const record = fixtures.state()
31
- const entity = new Entity(fixtures.schema, record, undefined, false)
62
+ const entity = new Entity(fixtures.schema, BLANK, record, undefined, false)
32
63
 
33
64
  // no pre-image to diff against, hence no copy of it
34
65
  assert.strictEqual(entity.get(), record)
35
66
  })
36
67
 
37
68
  it('should still report a tombstone', () => {
38
- const record = { ...fixtures.state(), _deleted: Date.now() }
39
- const entity = new Entity(fixtures.schema, record, undefined, false)
69
+ const record = { ...fixtures.state(), DELETED: Date.now() }
70
+ const entity = new Entity(fixtures.schema, BLANK, record, undefined, false)
40
71
 
41
72
  assert.strictEqual(entity.deleted, true)
42
73
  })
43
74
 
44
75
  it('should refuse to be modified', () => {
45
- const entity = new Entity(fixtures.schema, fixtures.state(), undefined, false)
76
+ const entity = new Entity(fixtures.schema, BLANK, fixtures.state(), undefined, false)
46
77
 
47
- assert.throws(() => entity.set(entity.get()), (error) => /read-only/.test(error.message))
78
+ assert.throws(
79
+ () => entity.set(entity.get()),
80
+ (error) => /read-only/.test(error.message)
81
+ )
48
82
  })
49
83
  })
50
84
 
51
85
  describe('tombstone', () => {
52
- it('should lift tombstone when transition leaves _deleted untouched', () => {
86
+ it('should lift tombstone when transition leaves DELETED untouched', () => {
53
87
  const origin = fixtures.state()
54
- const entity = new Entity(fixtures.schema, origin)
88
+ const entity = new Entity(fixtures.schema, BLANK, origin)
55
89
  const state = entity.get()
56
90
 
57
91
  state.foo = 'revived'
58
92
  entity.set(state)
59
93
 
60
- assert.strictEqual(entity.get()._deleted, null)
94
+ assert.strictEqual(entity.get().DELETED, null)
61
95
  assert.strictEqual(entity.deleted, false)
62
- assert.strictEqual(entity.event().state._deleted, null)
96
+ assert.strictEqual(entity.event().state.DELETED, null)
63
97
  })
64
98
 
65
99
  it('should keep tombstone written by transition', () => {
66
- const origin = { ...fixtures.state(), _deleted: null }
67
- const entity = new Entity(fixtures.schema, origin)
100
+ const origin = { ...fixtures.state(), DELETED: null }
101
+ const entity = new Entity(fixtures.schema, BLANK, origin)
68
102
  const state = entity.get()
69
103
  const timestamp = Date.now()
70
104
 
71
- state._deleted = timestamp
105
+ state.DELETED = timestamp
72
106
  entity.set(state)
73
107
 
74
- assert.strictEqual(entity.get()._deleted, timestamp)
108
+ assert.strictEqual(entity.get().DELETED, timestamp)
75
109
  assert.strictEqual(entity.deleted, true)
76
110
  })
77
111
  })
78
112
 
79
113
  it('should provide event', () => {
80
114
  const origin = fixtures.state()
81
- const entity = new Entity(fixtures.schema, origin)
115
+ const entity = new Entity(fixtures.schema, BLANK, origin)
82
116
  const state = entity.get()
83
117
 
84
118
  state.foo = 'new value'
@@ -88,11 +122,11 @@ it('should provide event', () => {
88
122
 
89
123
  assert.partialDeepStrictEqual(event, { state, origin })
90
124
  assert.strictEqual(event.state.foo, 'new value')
91
- assert.strictEqual(event.state._version, 1)
125
+ assert.strictEqual(event.state.VERSION, 1)
92
126
  assert.notStrictEqual(event.origin.foo, 'new value')
93
127
  })
94
128
 
95
- function resetCalls (target = [assert, fixtures], seen = new Set()) {
129
+ function resetCalls(target = [assert, fixtures], seen = new Set()) {
96
130
  if (target === null || typeof target !== 'object' || seen.has(target)) return
97
131
 
98
132
  seen.add(target)
@@ -2,11 +2,18 @@ import { mock } from 'node:test'
2
2
 
3
3
  import randomstring from 'randomstring'
4
4
 
5
- const schema = { [randomstring.generate()]: randomstring.generate() }
5
+ const schemas = {
6
+ entity: { [randomstring.generate()]: randomstring.generate() },
7
+ changeset: { [randomstring.generate()]: randomstring.generate() }
8
+ }
9
+
10
+ const blank = { [randomstring.generate()]: randomstring.generate() }
6
11
  const storage = { id: mock.fn(() => randomstring.generate()) }
7
12
  const entity = { [randomstring.generate()]: randomstring.generate() }
8
- const set = Array.from(Array(5))
9
- .map((_, index) => ({ id: index, [randomstring.generate()]: randomstring.generate() }))
13
+ const set = Array.from(Array(5)).map((_, index) => ({
14
+ id: index,
15
+ [randomstring.generate()]: randomstring.generate()
16
+ }))
10
17
 
11
18
  // node:test records a mock's calls but not the instances it constructed
12
19
  const entities = []
@@ -18,13 +25,7 @@ const Entity = mock.fn(function () {
18
25
 
19
26
  const EntitySet = mock.fn(function () {})
20
27
 
21
-
22
-
23
-
24
-
25
-
26
-
27
28
  // named `mock` for its consumers, which is what node:test calls its own tracker
28
29
  const mocks = { Entity, EntitySet }
29
30
 
30
- export { schema, storage, entity, set, entities, mocks as mock }
31
+ export { schemas, blank, storage, entity, set, entities, mocks as mock }
@@ -7,11 +7,14 @@ import { generate } from 'randomstring'
7
7
  import * as fixtures from './factory.fixtures.js'
8
8
  const mock = fixtures.mock
9
9
 
10
- mocking.module('../../src/entities/entity', { namedExports: ({ Entity: mock.Entity }) })
11
- mocking.module('../../src/entities/set', { namedExports: ({ EntitySet: mock.EntitySet }) })
12
-
13
- const { Factory } = await import('../../src/entities/factory.js')
10
+ mocking.module('../../source/entities/entity.js', {
11
+ namedExports: { Entity: mock.Entity }
12
+ })
13
+ mocking.module('../../source/entities/set.js', {
14
+ namedExports: { EntitySet: mock.EntitySet }
15
+ })
14
16
 
17
+ const { Factory } = await import('../../source/entities/factory.js')
15
18
 
16
19
  let factory
17
20
 
@@ -19,7 +22,7 @@ beforeEach(async () => {
19
22
  resetCalls()
20
23
  fixtures.entities.length = 0
21
24
 
22
- factory = new Factory(fixtures.schema, () => fixtures.storage.id())
25
+ factory = new Factory(fixtures.schemas, fixtures.blank, () => fixtures.storage.id())
23
26
  })
24
27
 
25
28
  it('should create initial', () => {
@@ -27,14 +30,33 @@ it('should create initial', () => {
27
30
  const initial = factory.init(id)
28
31
 
29
32
  assert.ok(initial instanceof mock.Entity)
30
- assert.ok(mock.Entity.mock.calls.some((call) => call.arguments.length === 3 && isDeepStrictEqual(call.arguments[0], fixtures.schema) && isDeepStrictEqual(call.arguments[1], id) && typeof call.arguments[2] === 'function'))
33
+ assert.ok(
34
+ mock.Entity.mock.calls.some(
35
+ (call) =>
36
+ call.arguments.length === 4 &&
37
+ isDeepStrictEqual(call.arguments[0], fixtures.schemas.entity) &&
38
+ isDeepStrictEqual(call.arguments[1], fixtures.blank) &&
39
+ isDeepStrictEqual(call.arguments[2], id) &&
40
+ typeof call.arguments[3] === 'function'
41
+ )
42
+ )
31
43
  })
32
44
 
33
45
  it('should create instance', () => {
34
46
  const object = factory.object(fixtures.entity)
35
47
 
36
48
  assert.ok(object instanceof mock.Entity)
37
- assert.ok(mock.Entity.mock.calls.some((call) => call.arguments.length === 4 && isDeepStrictEqual(call.arguments[0], fixtures.schema) && isDeepStrictEqual(call.arguments[1], fixtures.entity) && typeof call.arguments[2] === 'function' && isDeepStrictEqual(call.arguments[3], true)))
49
+ assert.ok(
50
+ mock.Entity.mock.calls.some(
51
+ (call) =>
52
+ call.arguments.length === 5 &&
53
+ isDeepStrictEqual(call.arguments[0], fixtures.schemas.entity) &&
54
+ isDeepStrictEqual(call.arguments[1], fixtures.blank) &&
55
+ isDeepStrictEqual(call.arguments[2], fixtures.entity) &&
56
+ typeof call.arguments[3] === 'function' &&
57
+ isDeepStrictEqual(call.arguments[4], true)
58
+ )
59
+ )
38
60
  })
39
61
 
40
62
  it('should create set', () => {
@@ -43,15 +65,30 @@ it('should create set', () => {
43
65
  assert.ok(objects instanceof mock.EntitySet)
44
66
 
45
67
  const instances = fixtures.set.map((entity, index) => {
46
- assert.ok(((call) => call.arguments.length === 4 && isDeepStrictEqual(call.arguments[0], fixtures.schema) && isDeepStrictEqual(call.arguments[1], entity) && typeof call.arguments[2] === 'function' && isDeepStrictEqual(call.arguments[3], true))(mock.Entity.mock.calls[index + 1 - 1] ?? { arguments: [] }))
68
+ assert.ok(
69
+ ((call) =>
70
+ call.arguments.length === 5 &&
71
+ isDeepStrictEqual(call.arguments[0], fixtures.schemas.entity) &&
72
+ isDeepStrictEqual(call.arguments[1], fixtures.blank) &&
73
+ isDeepStrictEqual(call.arguments[2], entity) &&
74
+ typeof call.arguments[3] === 'function' &&
75
+ isDeepStrictEqual(call.arguments[4], true))(
76
+ mock.Entity.mock.calls[index + 1 - 1] ?? { arguments: [] }
77
+ )
78
+ )
47
79
 
48
80
  return fixtures.entities[index]
49
81
  })
50
82
 
51
- assert.ok(mock.EntitySet.mock.calls.some((call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], instances)))
83
+ assert.ok(
84
+ mock.EntitySet.mock.calls.some(
85
+ (call) =>
86
+ call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], instances)
87
+ )
88
+ )
52
89
  })
53
90
 
54
- function resetCalls (target = [assert, fixtures, mock], seen = new Set()) {
91
+ function resetCalls(target = [assert, fixtures, mock], seen = new Set()) {
55
92
  if (target === null || typeof target !== 'object' || seen.has(target)) return
56
93
 
57
94
  seen.add(target)
@@ -1,7 +1,7 @@
1
1
  import { it } from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
3
 
4
- import { EntitySet } from '../../src/entities/set.js'
4
+ import { EntitySet } from '../../source/entities/set.js'
5
5
  import * as fixtures from './set.fixtures.js'
6
6
 
7
7
  it('should provide state', () => {