@reventlessdev/reventless-core 3.0.0-alpha.260 → 3.0.0-alpha.262

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 (208) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/package.json +10 -10
  3. package/src/Behavior.res +1 -4
  4. package/src/Message.res +17 -14
  5. package/src/Projection.res +51 -25
  6. package/src/RequestContext.res +8 -9
  7. package/src/ResourceAttribution.res +28 -14
  8. package/src/adapter/Adapter.res +48 -4
  9. package/src/adapter/EventLogProvisioning/EventLogProvisioning.res +5 -5
  10. package/src/adapter/Messaging/Messaging_Log_Backend.res +10 -7
  11. package/src/adapter/Messaging/Messaging_Log_Backend.res.mjs +2 -4
  12. package/src/adapter/Monitoring/Monitoring.res +16 -17
  13. package/src/adapter/QueryInterception/QueryInterception.res +0 -1
  14. package/src/adapter/Runtime/AggregateRuntime_Builder_Common.res +12 -5
  15. package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +11 -7
  16. package/src/adapter/Runtime/PluginRuntime_Builder_Micro.res +1 -7
  17. package/src/adapter/Runtime/PluginRuntime_Builder_Single.res +1 -7
  18. package/src/adapter/RuntimeExtension/RuntimeExtension.res +0 -1
  19. package/src/adapter/Secrets/Secrets_Node_Backend.res +60 -0
  20. package/src/adapter/Secrets/Secrets_Node_Backend.res.mjs +69 -0
  21. package/src/admin/Platform_Admin.res +17 -6
  22. package/src/admin/Platform_AdminApi.res +14 -9
  23. package/src/admin/Platform_Admin_Callback.res +1 -1
  24. package/src/admin/Platform_BakedManifest.res +34 -34
  25. package/src/admin/Platform_ComponentDefinitionsApi.res +9 -21
  26. package/src/admin/Platform_PluginStructuresApi.res +15 -12
  27. package/src/admin/UiFragmentRegistry/StateChange/UiFragmentRegistry.res +1 -1
  28. package/src/components/Aggregate/Aggregate.res +13 -12
  29. package/src/components/Aggregate/Aggregate_Builder.res +22 -21
  30. package/src/components/Aggregate/Aggregate_Callback.res +91 -86
  31. package/src/components/Api/ApiNoApiHelpers.res +1 -3
  32. package/src/components/Api/Api_Ids.res +0 -1
  33. package/src/components/Api/Api_Naming.res +41 -18
  34. package/src/components/Api/GraphQL_FragmentGenerator.res +38 -51
  35. package/src/components/Api/GraphQL_SchemaInspector.res +5 -3
  36. package/src/components/Api/GraphQL_Stitcher.res +9 -10
  37. package/src/components/Api/MCP_SchemaGenerator.res +8 -12
  38. package/src/components/Api/OwnerScopeDiagnostics.res +1 -2
  39. package/src/components/Api/QueryDbListQuery.res +13 -6
  40. package/src/components/Api/SchemaType.res +28 -23
  41. package/src/components/Api/SuryToJsonSchema.res +9 -10
  42. package/src/components/AutomationSlice/AutomationSlice.res +4 -4
  43. package/src/components/AutomationSlice/AutomationSlice_Builder.res +15 -14
  44. package/src/components/AutomationSlice/AutomationSlice_Callback.res +3 -3
  45. package/src/components/Builder_Helpers.res +12 -23
  46. package/src/components/CommandGenerator/CommandGenerator.res +6 -1
  47. package/src/components/CommandGenerator/CommandGenerator_Builder.res +29 -21
  48. package/src/components/CommandGenerator/CommandGenerator_Callback.res +17 -21
  49. package/src/components/CommandTopic/CommandTopic.res +3 -3
  50. package/src/components/CommandTopic/CommandTopic_Builder.res +10 -10
  51. package/src/components/CommandTopic/CommandTopic_Callback.res +1 -4
  52. package/src/components/CommandTopic/CommandTopic_Helpers.res +1 -2
  53. package/src/components/Counter/Counter_Builder.res +1 -6
  54. package/src/components/Counter/Counter_Callback.res +3 -3
  55. package/src/components/Dcb/Dcb_Builder.res +970 -956
  56. package/src/components/DcbEventLog/DcbEventLog.res +4 -4
  57. package/src/components/DcbEventLog/DcbEventLog_Builder.res +0 -1
  58. package/src/components/DcbEventLog/DcbEventLog_Operations.res +17 -18
  59. package/src/components/EventCollector/EventCollector_Builder.res +2 -1
  60. package/src/components/EventLog/EventLog.res +5 -1
  61. package/src/components/EventLog/EventLog_Operations.res +12 -8
  62. package/src/components/EventMapper/EventMapper.res +8 -10
  63. package/src/components/EventMapper/EventMapper_Builder.res +4 -1
  64. package/src/components/EventMapper/EventMapper_Callback.res +46 -31
  65. package/src/components/EventTopic/EventTopic.res +3 -3
  66. package/src/components/EventTopic/EventTopic_Builder.res +1 -1
  67. package/src/components/Extension/Extension.res +4 -1
  68. package/src/components/Extension/Extension_Operations.res +11 -3
  69. package/src/components/ExtensionPoint/ExtensionPoint.res +3 -3
  70. package/src/components/ExtensionPoint/ExtensionPoint_Builder.res +9 -10
  71. package/src/components/ExtensionPoint/ExtensionPoint_Callback.res +2 -6
  72. package/src/components/ExtensionPoint/ExtensionPoint_Operations.res +13 -5
  73. package/src/components/Heartbeat/Heartbeat_Callback.res +3 -3
  74. package/src/components/InboundTranslationSlice/InboundTranslationSlice.res +4 -4
  75. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Builder.res +7 -10
  76. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice.res +4 -4
  77. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res +15 -14
  78. package/src/components/QueryDb/QueryDb_Adapter.res +1 -3
  79. package/src/components/QueryDb/QueryDb_Operations.res +10 -10
  80. package/src/components/ReadModel/ReadModel.res +3 -3
  81. package/src/components/ReadModel/ReadModel_Builder.res +1 -2
  82. package/src/components/ReadModel/ReadModel_Callback.res +2 -1
  83. package/src/components/SideEffectHandler/SideEffectHandler_Callback.res +5 -2
  84. package/src/components/StateChangeSlice/StateChangeSlice.res +3 -3
  85. package/src/components/StateChangeSlice/StateChangeSlice_Builder.res +23 -4
  86. package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +22 -6
  87. package/src/components/StateTopic.res +1 -3
  88. package/src/components/StateViewSlice/StateViewSlice.res +4 -4
  89. package/src/components/StateViewSlice/StateViewSlice_Builder.res +79 -68
  90. package/src/components/StateViewSlice/StateViewSlice_Callback.res +3 -1
  91. package/src/components/Task/Task.res +3 -3
  92. package/src/components/Task/Task_Adapter.res +4 -1
  93. package/src/components/Task/Task_Builder.res +24 -21
  94. package/src/plugin/api/PluginBaseFragment.res +9 -3
  95. package/src/plugin/component/Capability_Inference.res +8 -10
  96. package/src/plugin/component/Plugin.res +6 -6
  97. package/src/plugin/component/Plugin_Builder.res +54 -50
  98. package/src/plugin/component/Plugin_Callback.res +10 -6
  99. package/src/plugin/component/Plugin_Helpers.res +264 -230
  100. package/src/plugin/component/Plugin_Structure.res +370 -324
  101. package/src/plugin/component/Plugin_SubscriptionSchema.res +8 -6
  102. package/src/plugin/component/SchemaWalker.res +11 -12
  103. package/src/plugin/connect/PluginConnectExtension_Mapping.res +45 -50
  104. package/src/plugin/lifecycle/PluginBehavior.res +3 -4
  105. package/src/plugin/lifecycle/PluginSpec.res +1 -2
  106. package/src/plugin/lifecycle/PluginsProjection.res +16 -5
  107. package/src/plugin/lifecycle/PluginsReadModelSpec.res +0 -2
  108. package/src/util/CommandPublisher.res +9 -2
  109. package/src/util/CsvStream.res +3 -3
  110. package/src/util/Interstack.res +7 -15
  111. package/src/util/Interstack.resi +3 -3
  112. package/src/util/LogFormat.res +5 -9
  113. package/src/util/Logger.res +1 -2
  114. package/src/util/Lru.res +2 -1
  115. package/src/util/Lru.resi +2 -3
  116. package/src/util/ScheduleOps.res +24 -27
  117. package/src/util/StorePrefixCollision.res +6 -9
  118. package/src/util/Util_Promise.res +4 -1
  119. package/src/util/Util_Promise.res.mjs +1 -1
  120. package/tests/IdentityTest.res +166 -113
  121. package/tests/ResourceAttributionTest.res +28 -25
  122. package/tests/Secrets_Node_BackendTest.res +141 -0
  123. package/tests/Secrets_Node_BackendTest.res.mjs +152 -0
  124. package/tests/StorePrefixCollisionTest.res +2 -1
  125. package/tests/TaskBucketNamingTest.res +3 -2
  126. package/tests/adapter/EventLogProvisioningTest.res +51 -48
  127. package/tests/adapter/MonitoringTest.res +81 -38
  128. package/tests/adapter/QueryInterceptionTest.res +2 -2
  129. package/tests/adapter/RefusalVocabularyTest.res +31 -23
  130. package/tests/adapter/RuntimeExtensionHookReachTest.res +9 -8
  131. package/tests/adapter/RuntimeExtensionTest.res +5 -3
  132. package/tests/admin/AdminApiSchemaDriftTest.res +22 -16
  133. package/tests/admin/Platform_Admin_StructureTest.res +22 -14
  134. package/tests/admin/Platform_Admin_StructureTest.res.mjs +4 -3
  135. package/tests/admin/Platform_BakedManifestTest.res +31 -35
  136. package/tests/admin/Platform_ComponentDefinitionsApiTest.res +18 -15
  137. package/tests/admin/Platform_PluginStructuresApiTest.res +5 -3
  138. package/tests/admin/Platform_UIFragmentsApiTest.res +6 -3
  139. package/tests/aggregate/AggregateCacheTest.res +10 -12
  140. package/tests/aggregate/AggregateCallbackTest.res +75 -46
  141. package/tests/aggregate/AggregateCausationTest.res +19 -20
  142. package/tests/aggregate/AggregateConflictTest.res +41 -19
  143. package/tests/aggregate/AggregateFixtures.res +15 -5
  144. package/tests/aggregate/AggregateRejectionTest.res +97 -80
  145. package/tests/aggregate/AggregateSnapshotTest.res +44 -16
  146. package/tests/api/Api_IdsTest.res +10 -4
  147. package/tests/api/BrandedMarkerCompositionTest.res +48 -36
  148. package/tests/api/GeolocationSemanticTest.res +3 -3
  149. package/tests/api/GraphQL_FragmentGeneratorTest.res +66 -54
  150. package/tests/api/OwnerScopeDiagnosticsTest.res +31 -27
  151. package/tests/api/StorageRefFieldsTest.res +30 -18
  152. package/tests/api/SuryToJsonSchemaTest.res +1315 -1014
  153. package/tests/api/TaggedUnionSchemaTest.res +17 -24
  154. package/tests/commandgenerator/CommandGeneratorCallbackTest.res +235 -179
  155. package/tests/commandgenerator/CommandGeneratorFixtures.res +8 -13
  156. package/tests/commandgenerator/OwnerStampingTest.res +91 -76
  157. package/tests/commandtopic/CommandOutcomeHookTest.res +198 -155
  158. package/tests/commandtopic/CommandTopicCallbackFixtures.res +5 -4
  159. package/tests/commandtopic/CommandTopicCallbackTest.res +61 -43
  160. package/tests/commandtopic/CommandTopicHelpersRejectionTest.res +70 -55
  161. package/tests/counter/CounterCallbackTest.res +40 -34
  162. package/tests/counter/CounterFixtures.res +4 -4
  163. package/tests/dcb/DcbDecodeTest.res +115 -84
  164. package/tests/dcb/DcbEventLogOperationsTest.res +194 -143
  165. package/tests/dcb/DcbEventLogSchemaTest.res +13 -13
  166. package/tests/dcb/DcbFixtures.res +4 -5
  167. package/tests/dcb/DcbScopeInferenceTest.res +173 -114
  168. package/tests/dcb/DcbStateChangeSliceTest.res +391 -262
  169. package/tests/dcb/DcbTagTest.res +22 -11
  170. package/tests/dcb/DcbValidationTest.res +288 -218
  171. package/tests/eventlog/EventLogFixtures.res +4 -4
  172. package/tests/eventlog/EventLogOperationsTest.res +102 -67
  173. package/tests/eventlog/EventLogRetryTest.res +104 -65
  174. package/tests/eventmapper/EventMapperCallbackTest.res +118 -83
  175. package/tests/eventmapper/EventMapperFixtures.res +15 -23
  176. package/tests/eventmapper/EventMapperTest.res +54 -38
  177. package/tests/eventtopic/EventTopicFixtures.res +3 -4
  178. package/tests/eventtopic/EventTopicOperationsTest.res +41 -29
  179. package/tests/extensionpoint/ExtensionPointCallbackTest.res +58 -45
  180. package/tests/extensionpoint/ExtensionPointFixtures.res +16 -20
  181. package/tests/extensionpoint/ExtensionPointOperationsTest.res +70 -49
  182. package/tests/extensionpoint/PluginDisconnectScheduleTest.res +2 -1
  183. package/tests/logger/LogFormatTest.res +104 -82
  184. package/tests/logger/LoggerLazyTest.res +21 -12
  185. package/tests/message/MessageTest.res +96 -93
  186. package/tests/message/MetaEnvelopeTest.res +26 -30
  187. package/tests/plugin/HeartbeatDisconnectGraceTest.res +31 -25
  188. package/tests/plugin/ManifestVisibilityTest.res +20 -12
  189. package/tests/plugin/PluginDefinitionScalars.res +1 -2
  190. package/tests/plugin/PluginLifecycleCorpusTest.res +15 -12
  191. package/tests/plugin/PluginSpecExperiment.res +0 -1
  192. package/tests/plugin/PluginStructureTest.res +1529 -1045
  193. package/tests/plugin/Plugin_EventQuerySchemaTest.res +21 -10
  194. package/tests/plugin/SchemaWalkerTest.res +116 -70
  195. package/tests/plugin/StateChange/PsReserveStock.res +4 -4
  196. package/tests/plugin/StateView/PsAnnotatedView.res +4 -4
  197. package/tests/plugin/StateView/PsCustomersView.res +4 -4
  198. package/tests/plugin/StateView/PsShipmentsView.res +3 -2
  199. package/tests/projection/LifecycleTrailTest.res +1 -4
  200. package/tests/projection/ProjectionOptimizeTest.res +13 -9
  201. package/tests/querydb/QueryDbFixtures.res +0 -1
  202. package/tests/querydb/QueryDbOperationsTest.res +99 -64
  203. package/tests/querydb/TaggedUnionStampTest.res +10 -8
  204. package/tests/sideeffecthandler/SideEffectHandlerCallbackTest.res +50 -35
  205. package/tests/sideeffecthandler/SideEffectHandlerFixtures.res +4 -10
  206. package/tests/util/CommandPublisherTest.res +0 -1
  207. package/tests/util/CsvStreamTest.res +3 -3
  208. package/tests/util/LruTest.res +84 -56
@@ -44,8 +44,7 @@ describe("the Plugins read model declares its lifecycle", () => {
44
44
  })
45
45
 
46
46
  testSync("is served on the encoded def under the new key", () => {
47
- let json =
48
- rm->Platform_ComponentDefinitionsApi.encodeQueryableDef->JSON.stringify
47
+ let json = rm->Platform_ComponentDefinitionsApi.encodeQueryableDef->JSON.stringify
49
48
  expect(json->String.includes(`"lifecycleField":"status"`))->toEqual(true)
50
49
  })
51
50
 
@@ -137,11 +136,7 @@ describe("the Plugin command defs carry every argument the SDL requires", () =>
137
136
  Platform_Admin_Structure.pluginCommands
138
137
  ->Array.filter(c => c.apiExposed != Some(false))
139
138
  ->Array.map(c => c.mutationField),
140
- )->toEqual([
141
- "Platform_Plugin_Activate",
142
- "Platform_Plugin_Deactivate",
143
- "Platform_Plugin_Retire",
144
- ])
139
+ )->toEqual(["Platform_Plugin_Activate", "Platform_Plugin_Deactivate", "Platform_Plugin_Retire"])
145
140
  )
146
141
 
147
142
  // The `@noApi` protocol variants come back from the same walk. They belong on
@@ -179,16 +174,20 @@ describe("the internal commands declare the edges they move rows along", () => {
179
174
  }
180
175
 
181
176
  testSync("the only edge into Disconnected is declared", () =>
182
- expect((commandNamed("Disconnect").allowedStates, commandNamed("Disconnect").targetState))
183
- ->toEqual((Some(["Connected"]), Some("Disconnected")))
177
+ expect((
178
+ commandNamed("Disconnect").allowedStates,
179
+ commandNamed("Disconnect").targetState,
180
+ ))->toEqual((Some(["Connected"]), Some("Disconnected")))
184
181
  )
185
182
 
186
183
  // The creating form's claim: a target and no from-set. `Connect` brings the
187
184
  // version's row into being, so there is no state it runs from — and an empty
188
185
  // `allowedStates` would say the opposite, that it is legal in none.
189
186
  testSync("the handshake declares a target and no from-set", () =>
190
- expect((commandNamed("Connect").allowedStates, commandNamed("Connect").targetState))
191
- ->toEqual((None, Some("Connected")))
187
+ expect((commandNamed("Connect").allowedStates, commandNamed("Connect").targetState))->toEqual((
188
+ None,
189
+ Some("Connected"),
190
+ ))
192
191
  )
193
192
 
194
193
  testSync("and no state is left unreachable", () =>
@@ -207,14 +206,23 @@ describe("the internal commands declare the edges they move rows along", () => {
207
206
  // was open to everyone and the server refused anyone outside `Admin`. The
208
207
  // mismatch is invisible until a non-admin clicks the page.
209
208
  describe("the Plugins view publishes the rule the server enforces", () => {
210
- testSync("the spec declares the group", () =>
209
+ // 🚨 **This is also the only check `Reventless.AdminGroup.name` can carry.** A
210
+ // PPX annotation takes a literal, so `@@reventless.authorize(AllowGroups(
211
+ // ["Admin"]))` above cannot reference the constant — the constant's job is to
212
+ // make everything *else* agree with the annotation, and nothing in the compiler
213
+ // spans that gap. The actual side here comes from the expanded annotation and
214
+ // the expected side from the constant, so the two are compared rather than
215
+ // restated. Writing the literal on both sides would pass while they diverged.
216
+ testSync("the spec declares the group, and it is the one the constant names", () =>
211
217
  expect(PluginsReadModelSpec.authorization)->toEqual(
212
- Reventless.Authorization.AllowGroups(["Admin"]),
218
+ Reventless.Authorization.AllowGroups([Reventless.AdminGroup.name]),
213
219
  )
214
220
  )
215
221
 
216
222
  testSync("and the published access keys are derived from it", () =>
217
- expect(Platform_Admin_Structure.pluginReadModel.requiredAccess)->toEqual(Some(["Admin"]))
223
+ expect(Platform_Admin_Structure.pluginReadModel.requiredAccess)->toEqual(
224
+ Some([Reventless.AdminGroup.name]),
225
+ )
218
226
  )
219
227
 
220
228
  // The API entry reads the same binding rather than restating it, so the two
@@ -3,6 +3,7 @@
3
3
  import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
4
4
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
5
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
6
+ import * as AdminGroup$Reventless from "@reventlessdev/reventless-spec/src/types/AdminGroup.res.mjs";
6
7
  import * as Plugin_Structure$ReventlessCore from "../../src/plugin/component/Plugin_Structure.res.mjs";
7
8
  import * as PluginBaseFragment$ReventlessCore from "../../src/plugin/api/PluginBaseFragment.res.mjs";
8
9
  import * as PluginsReadModelSpec$ReventlessCore from "../../src/plugin/lifecycle/PluginsReadModelSpec.res.mjs";
@@ -154,14 +155,14 @@ globalThis.describe("the internal commands declare the edges they move rows alon
154
155
  });
155
156
 
156
157
  globalThis.describe("the Plugins view publishes the rule the server enforces", () => {
157
- globalThis.test("the spec declares the group", () => {
158
+ globalThis.test("the spec declares the group, and it is the one the constant names", () => {
158
159
  globalThis.expect(PluginsReadModelSpec$ReventlessCore.authorization).toEqual({
159
160
  TAG: "AllowGroups",
160
- _0: ["Admin"]
161
+ _0: [AdminGroup$Reventless.name]
161
162
  });
162
163
  });
163
164
  globalThis.test("and the published access keys are derived from it", () => {
164
- globalThis.expect(Platform_Admin_Structure$ReventlessCore.pluginReadModel.requiredAccess).toEqual(["Admin"]);
165
+ globalThis.expect(Platform_Admin_Structure$ReventlessCore.pluginReadModel.requiredAccess).toEqual([AdminGroup$Reventless.name]);
165
166
  });
166
167
  globalThis.test("the query entry carries the spec's rule and no hand-written pair", () => {
167
168
  let entry = PluginBaseFragment$ReventlessCore.queryEntries[0];
@@ -91,8 +91,7 @@ let structure: pluginStructure = {
91
91
 
92
92
  let structures = [("Ordering@1.0.0", structure)]
93
93
 
94
- let bake = selections =>
95
- Platform_BakedManifest.curate(~structures, ~selections)
94
+ let bake = selections => Platform_BakedManifest.curate(~structures, ~selections)
96
95
 
97
96
  // Every case below varies one include-list and means "everything" by the rest,
98
97
  // which is exactly what an omitted labelled argument says.
@@ -112,7 +111,10 @@ let names = (entry: JSON.t, field: string) =>
112
111
  ->Option.flatMap(JSON.Decode.array)
113
112
  ->Option.getOr([])
114
113
  ->Array.filterMap(v =>
115
- v->JSON.Decode.object->Option.flatMap(d => d->Dict.get("name"))->Option.flatMap(JSON.Decode.string)
114
+ v
115
+ ->JSON.Decode.object
116
+ ->Option.flatMap(d => d->Dict.get("name"))
117
+ ->Option.flatMap(JSON.Decode.string)
116
118
  )
117
119
 
118
120
  let firstEntry = (r: result<JSON.t, Platform_BakedManifest.error>) =>
@@ -146,15 +148,13 @@ describe("curate", () => {
146
148
  // from, so an Internal view a kept command points at has to survive the bake.
147
149
  testSync("carries an Internal view referenced by an included command", () => {
148
150
  let entry =
149
- bake([sel(~plugin="Ordering", ~views=["Orders"], ~commands=["PlaceOrder"])])
150
- ->firstEntry
151
+ bake([sel(~plugin="Ordering", ~views=["Orders"], ~commands=["PlaceOrder"])])->firstEntry
151
152
  expect(entry->names("internalQueryables"))->toEqual(["AvailableProducts"])
152
153
  })
153
154
 
154
155
  testSync("omits an Internal view no included command references", () => {
155
156
  let entry =
156
- bake([sel(~plugin="Ordering", ~views=["Orders"], ~commands=["ImportOrders"])])
157
- ->firstEntry
157
+ bake([sel(~plugin="Ordering", ~views=["Orders"], ~commands=["ImportOrders"])])->firstEntry
158
158
  expect(entry->names("internalQueryables"))->toEqual([])
159
159
  })
160
160
 
@@ -193,9 +193,9 @@ describe("curate", () => {
193
193
  )
194
194
 
195
195
  testSync("accepts a kind this plugin generates no page for", () =>
196
- expect(
197
- bake([sel(~plugin="Ordering", ~derived=["scheduler"])])->firstEntry->derivedOf,
198
- )->toEqual(Some(["scheduler"]))
196
+ expect(bake([sel(~plugin="Ordering", ~derived=["scheduler"])])->firstEntry->derivedOf)->toEqual(
197
+ Some(["scheduler"]),
198
+ )
199
199
  )
200
200
 
201
201
  testSync("an Internal view is never selectable as a view", () =>
@@ -228,27 +228,26 @@ describe("curate", () => {
228
228
  })
229
229
 
230
230
  testSync("one entry per selection, in declaration order", () => {
231
- let json =
232
- Platform_BakedManifest.curate(
233
- ~structures=[("Ordering@1.0.0", structure), ("Catalog@1.0.0", structure)],
234
- ~selections=[
235
- sel(~plugin="Catalog", ~views=[], ~commands=[]),
236
- sel(~plugin="Ordering", ~views=[], ~commands=[]),
237
- ],
238
- )
239
- let ids =
240
- switch json {
241
- | Ok(j) =>
242
- j
243
- ->entries
244
- ->Array.filterMap(e =>
231
+ let json = Platform_BakedManifest.curate(
232
+ ~structures=[("Ordering@1.0.0", structure), ("Catalog@1.0.0", structure)],
233
+ ~selections=[
234
+ sel(~plugin="Catalog", ~views=[], ~commands=[]),
235
+ sel(~plugin="Ordering", ~views=[], ~commands=[]),
236
+ ],
237
+ )
238
+ let ids = switch json {
239
+ | Ok(j) =>
240
+ j
241
+ ->entries
242
+ ->Array.filterMap(
243
+ e =>
245
244
  e
246
245
  ->JSON.Decode.object
247
246
  ->Option.flatMap(d => d->Dict.get("pluginId"))
248
- ->Option.flatMap(JSON.Decode.string)
249
- )
250
- | Error(_) => []
251
- }
247
+ ->Option.flatMap(JSON.Decode.string),
248
+ )
249
+ | Error(_) => []
250
+ }
252
251
  expect(ids)->toEqual(["Catalog", "Ordering"])
253
252
  })
254
253
 
@@ -258,8 +257,7 @@ describe("curate", () => {
258
257
  // makes this hold — the assertion guards that property, not a second code path.
259
258
  testSync("a curated entry carries the owner field the served entry carries", () => {
260
259
  let entry =
261
- bake([sel(~plugin="Ordering", ~views=["Orders"], ~commands=["PlaceOrder"])])
262
- ->firstEntry
260
+ bake([sel(~plugin="Ordering", ~views=["Orders"], ~commands=["PlaceOrder"])])->firstEntry
263
261
  let ownerOf = (key, name) =>
264
262
  entry
265
263
  ->JSON.Decode.object
@@ -267,9 +265,7 @@ describe("curate", () => {
267
265
  ->Option.flatMap(JSON.Decode.array)
268
266
  ->Option.getOr([])
269
267
  ->Array.filterMap(JSON.Decode.object)
270
- ->Array.find(d =>
271
- d->Dict.get("name")->Option.flatMap(JSON.Decode.string) == Some(name)
272
- )
268
+ ->Array.find(d => d->Dict.get("name")->Option.flatMap(JSON.Decode.string) == Some(name))
273
269
  ->Option.flatMap(d => d->Dict.get("ownerField"))
274
270
  ->Option.flatMap(JSON.Decode.string)
275
271
  let commandOwner =
@@ -279,8 +275,8 @@ describe("curate", () => {
279
275
  ->Option.flatMap(JSON.Decode.array)
280
276
  ->Option.getOr([])
281
277
  ->Array.filterMap(JSON.Decode.object)
282
- ->Array.flatMap(w =>
283
- w->Dict.get("commands")->Option.flatMap(JSON.Decode.array)->Option.getOr([])
278
+ ->Array.flatMap(
279
+ w => w->Dict.get("commands")->Option.flatMap(JSON.Decode.array)->Option.getOr([]),
284
280
  )
285
281
  ->Array.filterMap(JSON.Decode.object)
286
282
  ->Array.get(0)
@@ -11,9 +11,7 @@ let cmd: commandDef = {
11
11
  level: Collection,
12
12
  aggregateIdField: None,
13
13
  mutationField: "AddProduct",
14
- references: [
15
- {fieldName: "categoryId", entity: "Category", plugin: Some("Catalog")},
16
- ],
14
+ references: [{fieldName: "categoryId", entity: "Category", plugin: Some("Catalog")}],
17
15
  allowedStates: None,
18
16
  targetState: None,
19
17
  apiExposed: Some(true),
@@ -276,10 +274,10 @@ describe("visibility filtering (deployed AutoUI hides Internal)", () => {
276
274
  idField: Some("productId"),
277
275
  idFieldSource: Some("sole"),
278
276
  requiredAccess: None,
279
- ownerField: None,
280
- retiredField: None,
281
- retiredValues: None,
282
- namedWhenRetired: None,
277
+ ownerField: None,
278
+ retiredField: None,
279
+ retiredValues: None,
280
+ namedWhenRetired: None,
283
281
  }
284
282
  // A distinct name per source array: the complement has to be fed by both, and
285
283
  // reusing one def would hide a version that only walks `readModels`.
@@ -293,8 +291,10 @@ describe("visibility filtering (deployed AutoUI hides Internal)", () => {
293
291
  readModels: [qbl, internalQbl],
294
292
  stateViewSlices: [internalSlice],
295
293
  }
296
- let mixedEntry =
297
- Platform_ComponentDefinitionsApi.encodePluginStructureEntry(~pluginId="Ordering", mixed)
294
+ let mixedEntry = Platform_ComponentDefinitionsApi.encodePluginStructureEntry(
295
+ ~pluginId="Ordering",
296
+ mixed,
297
+ )
298
298
 
299
299
  // Names under one key of the encoded entry. `String.includes` over the whole
300
300
  // JSON can no longer answer this: an Internal view is legitimately present
@@ -308,7 +308,10 @@ describe("visibility filtering (deployed AutoUI hides Internal)", () => {
308
308
  ->Option.flatMap(JSON.Decode.array)
309
309
  ->Option.getOr([])
310
310
  ->Array.filterMap(c =>
311
- c->JSON.Decode.object->Option.flatMap(o => o->Dict.get("name"))->Option.flatMap(JSON.Decode.string)
311
+ c
312
+ ->JSON.Decode.object
313
+ ->Option.flatMap(o => o->Dict.get("name"))
314
+ ->Option.flatMap(JSON.Decode.string)
312
315
  )
313
316
 
314
317
  testSync("excludes an Internal queryableDef from the encoded read-side", () => {
@@ -358,7 +361,7 @@ describe("allowedStates + lifecycleField populated", () => {
358
361
  allowedStatesSource: "declared",
359
362
  apiExposed: Some(true),
360
363
  requiredAccess: None,
361
- ownerField: None,
364
+ ownerField: None,
362
365
  }
363
366
 
364
367
  let qblWithStatus: queryableDef = {
@@ -377,10 +380,10 @@ describe("allowedStates + lifecycleField populated", () => {
377
380
  idField: None,
378
381
  idFieldSource: None,
379
382
  requiredAccess: None,
380
- ownerField: None,
381
- retiredField: None,
382
- retiredValues: None,
383
- namedWhenRetired: None,
383
+ ownerField: None,
384
+ retiredField: None,
385
+ retiredValues: None,
386
+ namedWhenRetired: None,
384
387
  }
385
388
 
386
389
  let wblWithStates: writableDef = {
@@ -84,7 +84,10 @@ let namesOf = (key): array<string> =>
84
84
  ->Option.flatMap(JSON.Decode.array)
85
85
  ->Option.getOr([])
86
86
  ->Array.filterMap(v =>
87
- v->JSON.Decode.object->Option.flatMap(o => o->Dict.get("name"))->Option.flatMap(JSON.Decode.string)
87
+ v
88
+ ->JSON.Decode.object
89
+ ->Option.flatMap(o => o->Dict.get("name"))
90
+ ->Option.flatMap(JSON.Decode.string)
88
91
  )
89
92
 
90
93
  describe("Platform_PluginStructures entry", () => {
@@ -130,8 +133,7 @@ describe("Platform_PluginStructures entry", () => {
130
133
  expect(
131
134
  json->String.includes(
132
135
  "\"extensionPoints\":[{\"name\":\"Catalog.Products\",\"delegateNames\":[\"onAdded\"],\"sourceEventTypes\":[\"Catalog.ProductAdded\"],\"commandTypes\":null," ++
133
- "\"publishedEvents\":[{\"name\":\"Catalog.Products.ProductBecameAvailable\",\"fromEventTypes\":[\"Catalog.ProductAdded\"]}]," ++
134
- "\"acceptedCommands\":[{\"name\":\"Catalog.Products.Reserve\",\"toCommandTypes\":[\"Catalog.ReserveStock\"]}]}]",
136
+ "\"publishedEvents\":[{\"name\":\"Catalog.Products.ProductBecameAvailable\",\"fromEventTypes\":[\"Catalog.ProductAdded\"]}]," ++ "\"acceptedCommands\":[{\"name\":\"Catalog.Products.Reserve\",\"toCommandTypes\":[\"Catalog.ReserveStock\"]}]}]",
135
137
  ),
136
138
  )->toEqual(true)
137
139
  )
@@ -57,7 +57,9 @@ describe("encodeUIFragmentEntry", () => {
57
57
 
58
58
  testSync("encodes remoteEntryUrl", () =>
59
59
  expect(
60
- json->String.includes("\"remoteEntryUrl\":\"https://cdn.example.com/catalog@1.0/remoteEntry.js\""),
60
+ json->String.includes(
61
+ "\"remoteEntryUrl\":\"https://cdn.example.com/catalog@1.0/remoteEntry.js\"",
62
+ ),
61
63
  )->toEqual(true)
62
64
  )
63
65
 
@@ -80,8 +82,9 @@ describe("encodeUIFragmentEntry", () => {
80
82
 
81
83
  describe("Platform_UIFragmentsApi.sdl", () => {
82
84
  testSync("query field declares the list type", () =>
83
- expect(Platform_UIFragmentsApi.sdlQueryField->String.includes("[Platform_UIFragmentEntry!]!"))
84
- ->toEqual(true)
85
+ expect(
86
+ Platform_UIFragmentsApi.sdlQueryField->String.includes("[Platform_UIFragmentEntry!]!"),
87
+ )->toEqual(true)
85
88
  )
86
89
 
87
90
  testSync("sdlTypes includes Platform_UIFragmentEntry", () => {
@@ -12,7 +12,6 @@
12
12
 
13
13
  open JestGlobals
14
14
 
15
-
16
15
  module AggSpec = {
17
16
  module Id = Reventless.Id.StringPure
18
17
  let name = "CacheTestAggregate"
@@ -29,7 +28,7 @@ module AggSpec = {
29
28
  | CheckpointTaken({count: int})
30
29
 
31
30
  @schema
32
- type error = | Never
31
+ type error = Never
33
32
 
34
33
  let moduleUrl: string = %raw(`import.meta.url`)
35
34
  }
@@ -103,7 +102,7 @@ let makeMockEL = (): mockEL => {
103
102
  Error(EventLog.Conflict)
104
103
  } else {
105
104
  storedRef := storedRef.contents->Array.concat(newEvents)
106
- Ok(())
105
+ Ok()
107
106
  }
108
107
  }
109
108
 
@@ -155,11 +154,11 @@ module TestOps = {
155
154
  ) => promise<result<unit, EventLog.appendError>>,
156
155
  replay: string => promise<array<AggSpec.event>>,
157
156
  replayStream: (string, ~fromSeq: int=?) => Stream.t<AggSpec.event, string, unit>,
158
- appendStream: (int, string, Stream.t<AggSpec.event, string, unit>) => Effect.t<
159
- unit,
157
+ appendStream: (
158
+ int,
160
159
  string,
161
- unit,
162
- >,
160
+ Stream.t<AggSpec.event, string, unit>,
161
+ ) => Effect.t<unit, string, unit>,
163
162
  latestSnapshot: string => promise<result<option<EventLog.snapshot>, string>>,
164
163
  writeSnapshot: (string, EventLog.snapshot) => promise<result<unit, string>>,
165
164
  }
@@ -223,14 +222,13 @@ describe("Aggregate_Callback — replay cache:", () => {
223
222
  let _ = await run(AggSpec.Checkpoint)
224
223
  expect(mock.replayCallCount.contents)->toBe(2)
225
224
  // Both checkpoints observed the same state — cached fold ≡ replayed fold.
226
- let checkpoints =
227
- mock.getAll()
228
- ->Array.filterMap(e =>
225
+ let checkpoints = mock.getAll()->Array.filterMap(
226
+ e =>
229
227
  switch e.event {
230
228
  | CheckpointTaken({count}) => Some(count)
231
229
  | _ => None
232
- }
233
- )
230
+ },
231
+ )
234
232
  expect(checkpoints)->toEqual([3, 3])
235
233
  })
236
234
 
@@ -8,77 +8,106 @@ let _ = beforeEach(() => {
8
8
 
9
9
  describe("Aggregate_Callback.handleCommands:", () => {
10
10
  describe("single command — new aggregate", () => {
11
- testPromise("Create returns Ok(reference) and stores 1 event", async () => {
12
- let results = await Stream.fromIterable([
13
- makeTopicItem("ref-1", AggSpec.Create({name: "Widget"})),
14
- ])->TestHandler.handleCommands->Effect.runPromise
15
- expect((results, mock.getAll()->Array.length))->toEqual(([Ok("ref-1")], 1))
16
- })
11
+ testPromise(
12
+ "Create returns Ok(reference) and stores 1 event",
13
+ async () => {
14
+ let results = await Stream.fromIterable([
15
+ makeTopicItem("ref-1", AggSpec.Create({name: "Widget"})),
16
+ ])
17
+ ->TestHandler.handleCommands
18
+ ->Effect.runPromise
19
+ expect((results, mock.getAll()->Array.length))->toEqual(([Ok("ref-1")], 1))
20
+ },
21
+ )
17
22
  })
18
23
 
19
24
  describe("command on existing aggregate", () => {
20
- testPromise("Rename after Create replays history and appends new event", async () => {
21
- let _ =
22
- await Stream.fromIterable([
25
+ testPromise(
26
+ "Rename after Create replays history and appends new event",
27
+ async () => {
28
+ let _ = await Stream.fromIterable([
23
29
  makeTopicItem("ref-1", AggSpec.Create({name: "Widget"})),
24
- ])->TestHandler.handleCommands->Effect.runPromise
25
- let results =
26
- await Stream.fromIterable([
30
+ ])
31
+ ->TestHandler.handleCommands
32
+ ->Effect.runPromise
33
+ let results = await Stream.fromIterable([
27
34
  makeTopicItem("ref-2", AggSpec.Rename({newName: "Gadget"})),
28
- ])->TestHandler.handleCommands->Effect.runPromise
29
- expect((results, mock.getAll()->Array.length))->toEqual(([Ok("ref-2")], 2))
30
- })
35
+ ])
36
+ ->TestHandler.handleCommands
37
+ ->Effect.runPromise
38
+ expect((results, mock.getAll()->Array.length))->toEqual(([Ok("ref-2")], 2))
39
+ },
40
+ )
31
41
  })
32
42
 
33
43
  describe("behavior returns no events", () => {
34
- testPromise("Rename on new aggregate returns Ok with no event stored", async () => {
35
- // Rename on empty history: Behavior.decide(NotCreated, Rename) returns Error(NotFound)
36
- let results =
37
- await Stream.fromIterable([
44
+ testPromise(
45
+ "Rename on new aggregate returns Ok with no event stored",
46
+ async () => {
47
+ // Rename on empty history: Behavior.decide(NotCreated, Rename) returns Error(NotFound)
48
+ let results = await Stream.fromIterable([
38
49
  makeTopicItem("ref-1", AggSpec.Rename({newName: "Gadget"})),
39
- ])->TestHandler.handleCommands->Effect.runPromise
40
- expect((results, mock.getAll()->Array.length))->toEqual(([Ok("ref-1")], 0))
41
- })
50
+ ])
51
+ ->TestHandler.handleCommands
52
+ ->Effect.runPromise
53
+ expect((results, mock.getAll()->Array.length))->toEqual(([Ok("ref-1")], 0))
54
+ },
55
+ )
42
56
  })
43
57
 
44
58
  describe("append failure", () => {
45
- testPromise("eventLog.append fails → reference returned Error", async () => {
46
- mock.failNextAppend := true
47
- let results =
48
- await Stream.fromIterable([
59
+ testPromise(
60
+ "eventLog.append fails → reference returned Error",
61
+ async () => {
62
+ mock.failNextAppend := true
63
+ let results = await Stream.fromIterable([
49
64
  makeTopicItem("ref-1", AggSpec.Create({name: "Widget"})),
50
- ])->TestHandler.handleCommands->Effect.runPromise
51
- expect(results)->toEqual([Error("ref-1")])
52
- })
65
+ ])
66
+ ->TestHandler.handleCommands
67
+ ->Effect.runPromise
68
+ expect(results)->toEqual([Error("ref-1")])
69
+ },
70
+ )
53
71
  })
54
72
 
55
73
  describe("multiple commands for same aggregate ID", () => {
56
- testPromise("Create then Rename in one batch accumulate state correctly", async () => {
57
- let results =
58
- await Stream.fromIterable([
74
+ testPromise(
75
+ "Create then Rename in one batch accumulate state correctly",
76
+ async () => {
77
+ let results = await Stream.fromIterable([
59
78
  makeTopicItem(~aggId="agg-1", "ref-1", AggSpec.Create({name: "Widget"})),
60
79
  makeTopicItem(~aggId="agg-1", "ref-2", AggSpec.Rename({newName: "Gadget"})),
61
- ])->TestHandler.handleCommands->Effect.runPromise
62
- // Both commands for same ID processed sequentially
63
- expect((results, mock.getAll()->Array.length))->toEqual(([Ok("ref-1"), Ok("ref-2")], 2))
64
- })
80
+ ])
81
+ ->TestHandler.handleCommands
82
+ ->Effect.runPromise
83
+ // Both commands for same ID processed sequentially
84
+ expect((results, mock.getAll()->Array.length))->toEqual(([Ok("ref-1"), Ok("ref-2")], 2))
85
+ },
86
+ )
65
87
  })
66
88
 
67
89
  describe("commands for different aggregate IDs", () => {
68
- testPromise("each ID processed independently", async () => {
69
- let results =
70
- await Stream.fromIterable([
90
+ testPromise(
91
+ "each ID processed independently",
92
+ async () => {
93
+ let results = await Stream.fromIterable([
71
94
  makeTopicItem(~aggId="agg-a", "ref-a", AggSpec.Create({name: "Alpha"})),
72
95
  makeTopicItem(~aggId="agg-b", "ref-b", AggSpec.Create({name: "Beta"})),
73
- ])->TestHandler.handleCommands->Effect.runPromise
74
- expect((results->Array.length, mock.getAll()->Array.length))->toEqual((2, 2))
75
- })
96
+ ])
97
+ ->TestHandler.handleCommands
98
+ ->Effect.runPromise
99
+ expect((results->Array.length, mock.getAll()->Array.length))->toEqual((2, 2))
100
+ },
101
+ )
76
102
  })
77
103
 
78
104
  describe("empty batch", () => {
79
- testPromise("returns empty array", async () => {
80
- let results = await Stream.fromIterable([])->TestHandler.handleCommands->Effect.runPromise
81
- expect(results)->toEqual([])
82
- })
105
+ testPromise(
106
+ "returns empty array",
107
+ async () => {
108
+ let results = await Stream.fromIterable([])->TestHandler.handleCommands->Effect.runPromise
109
+ expect(results)->toEqual([])
110
+ },
111
+ )
83
112
  })
84
113
  })
@@ -15,37 +15,36 @@ let _ = beforeEach(() => {
15
15
 
16
16
  describe("Aggregate_Callback causation propagation:", () => {
17
17
  testPromise("event.meta.causationId = command.meta.msgId", async () => {
18
- let _ =
19
- await Stream.fromIterable([
20
- makeTopicItem("ref-1", AggSpec.Create({name: "Widget"})),
21
- ])->TestHandler.handleCommands->Effect.runPromise
18
+ let _ = await Stream.fromIterable([makeTopicItem("ref-1", AggSpec.Create({name: "Widget"}))])
19
+ ->TestHandler.handleCommands
20
+ ->Effect.runPromise
22
21
  let stored = mock.getAll()->Array.getUnsafe(0)
23
22
  expect(stored.meta.causationId)->toEqual(Some(testMeta.msgId))
24
23
  })
25
24
 
26
- testPromise("event.meta.correlationId = command.meta.correlationId (chain root stable)", async () => {
27
- let _ =
28
- await Stream.fromIterable([
29
- makeTopicItem("ref-1", AggSpec.Create({name: "Widget"})),
30
- ])->TestHandler.handleCommands->Effect.runPromise
31
- let stored = mock.getAll()->Array.getUnsafe(0)
32
- expect(stored.meta.correlationId)->toBe(testMeta.correlationId)
33
- })
25
+ testPromise(
26
+ "event.meta.correlationId = command.meta.correlationId (chain root stable)",
27
+ async () => {
28
+ let _ = await Stream.fromIterable([makeTopicItem("ref-1", AggSpec.Create({name: "Widget"}))])
29
+ ->TestHandler.handleCommands
30
+ ->Effect.runPromise
31
+ let stored = mock.getAll()->Array.getUnsafe(0)
32
+ expect(stored.meta.correlationId)->toBe(testMeta.correlationId)
33
+ },
34
+ )
34
35
 
35
36
  testPromise("event has a fresh msgId distinct from the command's msgId", async () => {
36
- let _ =
37
- await Stream.fromIterable([
38
- makeTopicItem("ref-1", AggSpec.Create({name: "Widget"})),
39
- ])->TestHandler.handleCommands->Effect.runPromise
37
+ let _ = await Stream.fromIterable([makeTopicItem("ref-1", AggSpec.Create({name: "Widget"}))])
38
+ ->TestHandler.handleCommands
39
+ ->Effect.runPromise
40
40
  let stored = mock.getAll()->Array.getUnsafe(0)
41
41
  expect(stored.meta.msgId == testMeta.msgId)->toBe(false)
42
42
  })
43
43
 
44
44
  testPromise("event inherits ip / user / service from the command's meta", async () => {
45
- let _ =
46
- await Stream.fromIterable([
47
- makeTopicItem("ref-1", AggSpec.Create({name: "Widget"})),
48
- ])->TestHandler.handleCommands->Effect.runPromise
45
+ let _ = await Stream.fromIterable([makeTopicItem("ref-1", AggSpec.Create({name: "Widget"}))])
46
+ ->TestHandler.handleCommands
47
+ ->Effect.runPromise
49
48
  let stored = mock.getAll()->Array.getUnsafe(0)
50
49
  expect(stored.meta.service)->toBe(testMeta.service)
51
50
  })