@reventlessdev/reventless-core 3.0.0-alpha.301 → 3.0.0-alpha.302
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.
- package/CHANGELOG.md +18 -0
- package/package.json +6 -6
- package/src/adapter/Runtime/AggregateRuntime_Builder.res +2 -2
- package/src/adapter/Runtime/AggregateRuntime_Builder_Common.res +10 -5
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +2 -2
- package/src/adapter/Runtime/EventCollectorRuntime_Builder.res +1 -1
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +8 -3
- package/src/adapter/Runtime/ExtensionPointRuntime_Builder.res +1 -1
- package/src/adapter/Runtime/PluginRuntime_Builder.res +3 -3
- package/src/adapter/Runtime/Runtime.res +10 -9
- package/src/adapter/Runtime/TaskRuntime_Builder.res +1 -1
- package/src/admin/Platform_Admin_Structure.res +3 -3
- package/src/admin/Platform_Admin_Structure.res.mjs +1 -1
- package/src/admin/Platform_BakedManifest.res +7 -7
- package/src/admin/Platform_BakedManifest.res.mjs +2 -2
- package/src/admin/Platform_ComponentDefinitionsApi.res +12 -12
- package/src/admin/Platform_ComponentDefinitionsApi.res.mjs +11 -11
- package/src/admin/Platform_PluginStructuresApi.res +6 -6
- package/src/admin/Platform_PluginStructuresApi.res.mjs +4 -4
- package/src/admin/UiFragmentRegistry/StateView/UiFragments.res.mjs +1 -4
- package/src/components/Api/SuryToJsonSchema.res +1 -1
- package/src/components/CommandGenerator/CommandGenerator.res +1 -1
- package/src/components/CommandGenerator/CommandGenerator_Adapter.res +6 -1
- package/src/components/CommandTopic/CommandTopic.res +2 -2
- package/src/components/CommandTopic/CommandTopic_Adapter.res +1 -1
- package/src/components/EventCollector/EventCollector.res +1 -1
- package/src/components/EventCollector/EventCollector_Adapter.res +1 -1
- package/src/components/Heartbeat/Heartbeat.res +1 -1
- package/src/components/ReadModel/ReadModel.res +1 -1
- package/src/components/StateViewSlice/StateViewSlice_Builder.res +2 -2
- package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +1 -1
- package/src/components/StateViewSlice/StateViewSlice_Callback.res +2 -2
- package/src/components/StateViewSlice/StateViewSlice_Callback.res.mjs +1 -1
- package/src/components/Task/Task_Adapter.res +1 -1
- package/src/components/Task/Task_Builder.res +1 -1
- package/src/plugin/component/Plugin_Builder.res +7 -7
- package/src/plugin/component/Plugin_Builder.res.mjs +3 -3
- package/src/plugin/component/Plugin_BuiltHook.res +1 -1
- package/src/plugin/component/Plugin_Structure.res +18 -18
- package/src/plugin/component/Plugin_Structure.res.mjs +8 -8
- package/tests/admin/AdminApiSchemaDriftTest.res +8 -8
- package/tests/admin/AdminApiSchemaDriftTest.res.mjs +54 -54
- package/tests/admin/Platform_Admin_StructureTest.res +10 -10
- package/tests/admin/Platform_Admin_StructureTest.res.mjs +5 -5
- package/tests/admin/Platform_BakedManifestTest.res +7 -7
- package/tests/admin/Platform_BakedManifestTest.res.mjs +9 -9
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +11 -11
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +5 -5
- package/tests/admin/Platform_PluginStructuresApiTest.res +3 -3
- package/tests/message/MessageTest.res +1 -1
- package/tests/plugin/ManifestVisibilityTest.res +2 -2
- package/tests/plugin/PluginStructureAccessTest.res.mjs +2 -2
- package/tests/plugin/PluginStructureTest.res +9 -9
- package/tests/plugin/PluginStructureTest.res.mjs +7 -7
- package/tests/plugin/StateView/PsAnnotatedView.res +1 -1
- package/tests/plugin/StateView/PsAnnotatedView.res.mjs +1 -4
- package/tests/plugin/StateView/PsAvailableProductsView.res.mjs +1 -4
- package/tests/plugin/StateView/PsCategoriesView.res.mjs +1 -4
- package/tests/plugin/StateView/PsCustomersView.res.mjs +1 -4
- package/tests/plugin/StateView/PsGatedView.res.mjs +1 -4
- package/tests/plugin/StateView/PsOrdersView.res.mjs +1 -4
- package/tests/plugin/StateView/PsShipmentsView.res.mjs +1 -4
|
@@ -27,7 +27,7 @@ let commandNamed = (name: string): commandDef =>
|
|
|
27
27
|
let activate = () => commandNamed("Activate")
|
|
28
28
|
|
|
29
29
|
describe("the Plugins read model declares its lifecycle", () => {
|
|
30
|
-
let rm:
|
|
30
|
+
let rm: readSideDef = Platform_Admin_Structure.pluginReadModel()
|
|
31
31
|
|
|
32
32
|
testSync("names the field commands branch on", () =>
|
|
33
33
|
expect(rm.lifecycleField)->toEqual(Some("status"))
|
|
@@ -44,14 +44,14 @@ 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 = rm->Platform_ComponentDefinitionsApi.
|
|
47
|
+
let json = rm->Platform_ComponentDefinitionsApi.encodeReadSideDef->JSON.stringify
|
|
48
48
|
expect(json->String.includes(`"lifecycleField":"status"`))->toEqual(true)
|
|
49
49
|
})
|
|
50
50
|
|
|
51
51
|
testSync("and never under the old one", () =>
|
|
52
52
|
expect(
|
|
53
53
|
rm
|
|
54
|
-
->Platform_ComponentDefinitionsApi.
|
|
54
|
+
->Platform_ComponentDefinitionsApi.encodeReadSideDef
|
|
55
55
|
->JSON.stringify
|
|
56
56
|
->String.includes(`"statusField"`),
|
|
57
57
|
)->toEqual(false)
|
|
@@ -73,10 +73,10 @@ describe("the admin structure's declared transitions are checked", () => {
|
|
|
73
73
|
d
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
let raises =
|
|
76
|
+
let raises = writeSides =>
|
|
77
77
|
switch Plugin_Structure.checkDeclaredTransitions(
|
|
78
78
|
~pluginName="Platform",
|
|
79
|
-
~
|
|
79
|
+
~writeSides,
|
|
80
80
|
~lifecycleStatesByView=statesByView(),
|
|
81
81
|
) {
|
|
82
82
|
| () => false
|
|
@@ -95,7 +95,7 @@ describe("the admin structure's declared transitions are checked", () => {
|
|
|
95
95
|
|
|
96
96
|
// A check that cannot fail is indistinguishable from one that is not running.
|
|
97
97
|
testSync("and a state the view does not declare is caught", () => {
|
|
98
|
-
let bogus: Reventless.Plugin.
|
|
98
|
+
let bogus: Reventless.Plugin.writeSideDef = {
|
|
99
99
|
...Platform_Admin_Structure.pluginAggregate,
|
|
100
100
|
commands: [
|
|
101
101
|
{
|
|
@@ -193,7 +193,7 @@ describe("the internal commands declare the edges they move rows along", () => {
|
|
|
193
193
|
testSync("and no state is left unreachable", () =>
|
|
194
194
|
expect(
|
|
195
195
|
Plugin_Structure.lifecycleTopologyFindings(
|
|
196
|
-
~
|
|
196
|
+
~writeSides=[Platform_Admin_Structure.pluginAggregate],
|
|
197
197
|
~lifecycleStatesByView=statesByView(),
|
|
198
198
|
),
|
|
199
199
|
)->toEqual([])
|
|
@@ -239,14 +239,14 @@ describe("the Plugins view publishes the rule the server enforces", () => {
|
|
|
239
239
|
})
|
|
240
240
|
})
|
|
241
241
|
|
|
242
|
-
// The `
|
|
242
|
+
// The `readSideDef` is derived from the spec, not hand-written. The analysis
|
|
243
243
|
// that preceded this expected the admin's naming to be bespoke and it is not:
|
|
244
244
|
// `Api_Naming.queryFieldNamesForReadModel` returns byte-identical names, because
|
|
245
245
|
// `singularize` already handles the plural-spec-name / singular-type shape that
|
|
246
246
|
// looked special. Asserted rather than assumed — the whole case for deriving
|
|
247
247
|
// rests on the generic helpers reaching the same answers.
|
|
248
|
-
describe("the Plugins
|
|
249
|
-
let rm:
|
|
248
|
+
describe("the Plugins readSideDef is what the generic helpers produce", () => {
|
|
249
|
+
let rm: readSideDef = Platform_Admin_Structure.pluginReadModel()
|
|
250
250
|
|
|
251
251
|
testSync("the field names are the generic ones", () =>
|
|
252
252
|
expect((rm.queryField, rm.singleQueryField))->toEqual((
|
|
@@ -28,11 +28,11 @@ globalThis.describe("the Plugins read model declares its lifecycle", () => {
|
|
|
28
28
|
globalThis.expect(sdlDeclaresStatus).toEqual(true);
|
|
29
29
|
});
|
|
30
30
|
globalThis.test("is served on the encoded def under the new key", () => {
|
|
31
|
-
let json = JSON.stringify(Platform_ComponentDefinitionsApi$ReventlessCore.
|
|
31
|
+
let json = JSON.stringify(Platform_ComponentDefinitionsApi$ReventlessCore.encodeReadSideDef(rm));
|
|
32
32
|
globalThis.expect(json.includes(`"lifecycleField":"status"`)).toEqual(true);
|
|
33
33
|
});
|
|
34
34
|
globalThis.test("and never under the old one", () => {
|
|
35
|
-
globalThis.expect(JSON.stringify(Platform_ComponentDefinitionsApi$ReventlessCore.
|
|
35
|
+
globalThis.expect(JSON.stringify(Platform_ComponentDefinitionsApi$ReventlessCore.encodeReadSideDef(rm)).includes(`"statusField"`)).toEqual(false);
|
|
36
36
|
});
|
|
37
37
|
});
|
|
38
38
|
|
|
@@ -45,9 +45,9 @@ globalThis.describe("the admin structure's declared transitions are checked", ()
|
|
|
45
45
|
});
|
|
46
46
|
return d;
|
|
47
47
|
};
|
|
48
|
-
let raises =
|
|
48
|
+
let raises = writeSides => {
|
|
49
49
|
try {
|
|
50
|
-
Plugin_Structure$ReventlessCore.checkDeclaredTransitions("Platform",
|
|
50
|
+
Plugin_Structure$ReventlessCore.checkDeclaredTransitions("Platform", writeSides, statesByView());
|
|
51
51
|
return false;
|
|
52
52
|
} catch (exn) {
|
|
53
53
|
return true;
|
|
@@ -187,7 +187,7 @@ globalThis.describe("the Plugins view publishes the rule the server enforces", (
|
|
|
187
187
|
});
|
|
188
188
|
});
|
|
189
189
|
|
|
190
|
-
globalThis.describe("the Plugins
|
|
190
|
+
globalThis.describe("the Plugins readSideDef is what the generic helpers produce", () => {
|
|
191
191
|
let rm = Platform_Admin_Structure$ReventlessCore.pluginReadModel();
|
|
192
192
|
globalThis.test("the field names are the generic ones", () => {
|
|
193
193
|
globalThis.expect([
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
open JestGlobals
|
|
7
7
|
open Reventless.Plugin
|
|
8
8
|
|
|
9
|
-
let
|
|
9
|
+
let readSide = (~name, ~visibility=?, ~ownerField=?, ()): readSideDef => {
|
|
10
10
|
name,
|
|
11
11
|
queryField: `Ordering_${name}`,
|
|
12
12
|
schema: "{}",
|
|
@@ -42,7 +42,7 @@ let command = (~name, ~references=[], ~ownerField=?, ()): commandDef => {
|
|
|
42
42
|
ownerField,
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
let
|
|
45
|
+
let writeSide = (~name, ~commands): writeSideDef => {
|
|
46
46
|
name,
|
|
47
47
|
commands,
|
|
48
48
|
linkedViews: [],
|
|
@@ -58,13 +58,13 @@ let writable = (~name, ~commands): writableDef => {
|
|
|
58
58
|
// denormalised product mirror a command @refs, one end-user command and one
|
|
59
59
|
// operator command.
|
|
60
60
|
let structure: pluginStructure = {
|
|
61
|
-
readModels: [
|
|
61
|
+
readModels: [readSide(~name="Customers", ())],
|
|
62
62
|
stateViewSlices: [
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
readSide(~name="Orders", ~ownerField="customerId", ()),
|
|
64
|
+
readSide(~name="AvailableProducts", ~visibility="Internal", ()),
|
|
65
65
|
],
|
|
66
66
|
stateChangeSlices: [
|
|
67
|
-
|
|
67
|
+
writeSide(
|
|
68
68
|
~name="PlaceOrder",
|
|
69
69
|
~commands=[
|
|
70
70
|
command(
|
|
@@ -75,7 +75,7 @@ let structure: pluginStructure = {
|
|
|
75
75
|
),
|
|
76
76
|
],
|
|
77
77
|
),
|
|
78
|
-
|
|
78
|
+
writeSide(~name="ImportOrders", ~commands=[command(~name="ImportOrders", ())]),
|
|
79
79
|
],
|
|
80
80
|
aggregates: [],
|
|
81
81
|
automationSlices: [],
|
|
@@ -8,7 +8,7 @@ import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js
|
|
|
8
8
|
import * as Platform_BakedManifest$ReventlessCore from "../../src/admin/Platform_BakedManifest.res.mjs";
|
|
9
9
|
import * as Platform_ComponentDefinitionsApi$ReventlessCore from "../../src/admin/Platform_ComponentDefinitionsApi.res.mjs";
|
|
10
10
|
|
|
11
|
-
function
|
|
11
|
+
function readSide(name, visibility, ownerField, param) {
|
|
12
12
|
return {
|
|
13
13
|
name: name,
|
|
14
14
|
queryField: `Ordering_` + name,
|
|
@@ -49,7 +49,7 @@ function command(name, referencesOpt, ownerField, param) {
|
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function
|
|
52
|
+
function writeSide(name, commands) {
|
|
53
53
|
return {
|
|
54
54
|
name: name,
|
|
55
55
|
commands: commands,
|
|
@@ -63,20 +63,20 @@ function writable(name, commands) {
|
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
let structure_readModels = [
|
|
66
|
+
let structure_readModels = [readSide("Customers", undefined, undefined, undefined)];
|
|
67
67
|
|
|
68
68
|
let structure_stateViewSlices = [
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
readSide("Orders", undefined, "customerId", undefined),
|
|
70
|
+
readSide("AvailableProducts", "Internal", undefined, undefined)
|
|
71
71
|
];
|
|
72
72
|
|
|
73
73
|
let structure_stateChangeSlices = [
|
|
74
|
-
|
|
74
|
+
writeSide("PlaceOrder", [command("PlaceOrder", [{
|
|
75
75
|
fieldName: "productIds",
|
|
76
76
|
entity: "AvailableProducts",
|
|
77
77
|
plugin: undefined
|
|
78
78
|
}], "customerId", undefined)]),
|
|
79
|
-
|
|
79
|
+
writeSide("ImportOrders", [command("ImportOrders", undefined, undefined, undefined)])
|
|
80
80
|
];
|
|
81
81
|
|
|
82
82
|
let structure_aggregates = [];
|
|
@@ -296,9 +296,9 @@ globalThis.describe("curate", () => {
|
|
|
296
296
|
});
|
|
297
297
|
|
|
298
298
|
export {
|
|
299
|
-
|
|
299
|
+
readSide,
|
|
300
300
|
command,
|
|
301
|
-
|
|
301
|
+
writeSide,
|
|
302
302
|
structure,
|
|
303
303
|
structures,
|
|
304
304
|
bake,
|
|
@@ -19,7 +19,7 @@ let cmd: commandDef = {
|
|
|
19
19
|
ownerField: None,
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
let qbl:
|
|
22
|
+
let qbl: readSideDef = {
|
|
23
23
|
name: "Products",
|
|
24
24
|
queryField: "Catalog_Products",
|
|
25
25
|
schema: "{}",
|
|
@@ -41,7 +41,7 @@ let qbl: queryableDef = {
|
|
|
41
41
|
namedWhenRetired: None,
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
let wbl:
|
|
44
|
+
let wbl: writeSideDef = {
|
|
45
45
|
name: "Product",
|
|
46
46
|
commands: [cmd],
|
|
47
47
|
linkedViews: ["Products"],
|
|
@@ -152,7 +152,7 @@ describe("encodePluginStructureEntry", () => {
|
|
|
152
152
|
expect(json->String.includes("\"plugin\":\"Catalog\""))->toEqual(true)
|
|
153
153
|
)
|
|
154
154
|
|
|
155
|
-
testSync("includes the
|
|
155
|
+
testSync("includes the readSideDef name", () =>
|
|
156
156
|
expect(json->String.includes("\"name\":\"Products\""))->toEqual(true)
|
|
157
157
|
)
|
|
158
158
|
|
|
@@ -177,12 +177,12 @@ describe("encodePluginStructureEntry", () => {
|
|
|
177
177
|
)
|
|
178
178
|
|
|
179
179
|
// Phase 6.3: write-side emitted-event field schemas.
|
|
180
|
-
testSync("encodes
|
|
180
|
+
testSync("encodes writeSideDef events", () =>
|
|
181
181
|
expect(json->String.includes("\"events\":[{\"name\":\"ProductAdded\""))->toEqual(true)
|
|
182
182
|
)
|
|
183
183
|
|
|
184
184
|
// The refusals a caller has to handle travel beside the facts it can observe.
|
|
185
|
-
testSync("encodes
|
|
185
|
+
testSync("encodes writeSideDef errors", () =>
|
|
186
186
|
expect(json->String.includes("\"errors\":[{\"name\":\"ProductAlreadyExists\""))->toEqual(true)
|
|
187
187
|
)
|
|
188
188
|
|
|
@@ -258,7 +258,7 @@ describe("visibility filtering (deployed AutoUI hides Internal)", () => {
|
|
|
258
258
|
// Internal ReadModels / StateViewSlices are carried in pluginStructure for developer
|
|
259
259
|
// tooling but must not surface in the UI definitions the deployed AutoUI builds its
|
|
260
260
|
// menu / pages from — see Plugin_Structure.res / Visibility.res.
|
|
261
|
-
let internalQbl:
|
|
261
|
+
let internalQbl: readSideDef = {
|
|
262
262
|
name: "AvailableProducts",
|
|
263
263
|
queryField: "Ordering_AvailableProducts",
|
|
264
264
|
schema: "{}",
|
|
@@ -281,7 +281,7 @@ describe("visibility filtering (deployed AutoUI hides Internal)", () => {
|
|
|
281
281
|
}
|
|
282
282
|
// A distinct name per source array: the complement has to be fed by both, and
|
|
283
283
|
// reusing one def would hide a version that only walks `readModels`.
|
|
284
|
-
let internalSlice:
|
|
284
|
+
let internalSlice: readSideDef = {
|
|
285
285
|
...internalQbl,
|
|
286
286
|
name: "PendingShipments",
|
|
287
287
|
queryField: "Ordering_PendingShipments",
|
|
@@ -314,12 +314,12 @@ describe("visibility filtering (deployed AutoUI hides Internal)", () => {
|
|
|
314
314
|
->Option.flatMap(JSON.Decode.string)
|
|
315
315
|
)
|
|
316
316
|
|
|
317
|
-
testSync("excludes an Internal
|
|
317
|
+
testSync("excludes an Internal readSideDef from the encoded read-side", () => {
|
|
318
318
|
expect(mixedEntry->namesAt("readModels"))->toEqual(["Products"])
|
|
319
319
|
expect(mixedEntry->namesAt("stateViewSlices"))->toEqual([])
|
|
320
320
|
})
|
|
321
321
|
|
|
322
|
-
testSync("keeps a Public
|
|
322
|
+
testSync("keeps a Public readSideDef", () =>
|
|
323
323
|
expect(mixedEntry->namesAt("readModels")->Array.includes("Products"))->toEqual(true)
|
|
324
324
|
)
|
|
325
325
|
|
|
@@ -364,7 +364,7 @@ describe("allowedStates + lifecycleField populated", () => {
|
|
|
364
364
|
ownerField: None,
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
-
let qblWithStatus:
|
|
367
|
+
let qblWithStatus: readSideDef = {
|
|
368
368
|
name: "Plugin",
|
|
369
369
|
queryField: "Platform_Plugins",
|
|
370
370
|
schema: "{}",
|
|
@@ -386,7 +386,7 @@ describe("allowedStates + lifecycleField populated", () => {
|
|
|
386
386
|
namedWhenRetired: None,
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
-
let wblWithStates:
|
|
389
|
+
let wblWithStates: writeSideDef = {
|
|
390
390
|
name: "Plugin",
|
|
391
391
|
commands: [cmdWithStates],
|
|
392
392
|
linkedViews: ["Plugin"],
|
|
@@ -197,7 +197,7 @@ globalThis.describe("encodePluginStructureEntry", () => {
|
|
|
197
197
|
globalThis.test("encodes Some plugin reference as its inner string", () => {
|
|
198
198
|
globalThis.expect(json.includes("\"plugin\":\"Catalog\"")).toEqual(true);
|
|
199
199
|
});
|
|
200
|
-
globalThis.test("includes the
|
|
200
|
+
globalThis.test("includes the readSideDef name", () => {
|
|
201
201
|
globalThis.expect(json.includes("\"name\":\"Products\"")).toEqual(true);
|
|
202
202
|
});
|
|
203
203
|
globalThis.test("includes the automation slice name", () => {
|
|
@@ -215,10 +215,10 @@ globalThis.describe("encodePluginStructureEntry", () => {
|
|
|
215
215
|
globalThis.test("encodes None lifecycleField as null", () => {
|
|
216
216
|
globalThis.expect(json.includes("\"lifecycleField\":null")).toEqual(true);
|
|
217
217
|
});
|
|
218
|
-
globalThis.test("encodes
|
|
218
|
+
globalThis.test("encodes writeSideDef events", () => {
|
|
219
219
|
globalThis.expect(json.includes("\"events\":[{\"name\":\"ProductAdded\"")).toEqual(true);
|
|
220
220
|
});
|
|
221
|
-
globalThis.test("encodes
|
|
221
|
+
globalThis.test("encodes writeSideDef errors", () => {
|
|
222
222
|
globalThis.expect(json.includes("\"errors\":[{\"name\":\"ProductAlreadyExists\"")).toEqual(true);
|
|
223
223
|
});
|
|
224
224
|
globalThis.test("declares Platform_ErrorDef and the errors field in the shared write-side SDL", () => {
|
|
@@ -342,11 +342,11 @@ globalThis.describe("visibility filtering (deployed AutoUI hides Internal)", ()
|
|
|
342
342
|
};
|
|
343
343
|
let mixedEntry = Platform_ComponentDefinitionsApi$ReventlessCore.encodePluginStructureEntry("Ordering", undefined, mixed);
|
|
344
344
|
let namesAt = (entry, key) => Stdlib_Array.filterMap(Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(entry), o => o[key]), Stdlib_JSON.Decode.array), []), c => Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(c), o => o["name"]), Stdlib_JSON.Decode.string));
|
|
345
|
-
globalThis.test("excludes an Internal
|
|
345
|
+
globalThis.test("excludes an Internal readSideDef from the encoded read-side", () => {
|
|
346
346
|
globalThis.expect(namesAt(mixedEntry, "readModels")).toEqual(["Products"]);
|
|
347
347
|
globalThis.expect(namesAt(mixedEntry, "stateViewSlices")).toEqual([]);
|
|
348
348
|
});
|
|
349
|
-
globalThis.test("keeps a Public
|
|
349
|
+
globalThis.test("keeps a Public readSideDef", () => {
|
|
350
350
|
globalThis.expect(namesAt(mixedEntry, "readModels").includes("Products")).toEqual(true);
|
|
351
351
|
});
|
|
352
352
|
globalThis.test("carries what the filter removed on internalQueryables", () => {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
open JestGlobals
|
|
8
8
|
open Reventless.Plugin
|
|
9
9
|
|
|
10
|
-
let publicRm:
|
|
10
|
+
let publicRm: readSideDef = {
|
|
11
11
|
name: "Products",
|
|
12
12
|
queryField: "Catalog_Products",
|
|
13
13
|
schema: "{}",
|
|
@@ -30,7 +30,7 @@ let publicRm: queryableDef = {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// The component `Platform_ComponentDefinitions` drops and this query must keep.
|
|
33
|
-
let internalRm:
|
|
33
|
+
let internalRm: readSideDef = {
|
|
34
34
|
...publicRm,
|
|
35
35
|
name: "ProductAudit",
|
|
36
36
|
queryField: "Catalog_ProductAudit",
|
|
@@ -138,7 +138,7 @@ describe("Platform_PluginStructures entry", () => {
|
|
|
138
138
|
)->toEqual(true)
|
|
139
139
|
)
|
|
140
140
|
|
|
141
|
-
// Both read-side queries share `
|
|
141
|
+
// Both read-side queries share `encodeReadSideDef`, so this asserts the singular
|
|
142
142
|
// name is not a ComponentDefinitions-only field: a developer tool building a detail
|
|
143
143
|
// query reads it from here.
|
|
144
144
|
testSync("encodes the singular query field beside the list one", () =>
|
|
@@ -158,7 +158,7 @@ describe("Message should", () => {
|
|
|
158
158
|
let json = event'->Message.encodeEvent'(S.string, PluginSpec.eventSchema)
|
|
159
159
|
|
|
160
160
|
// Simulate the persisted JSON as written before these fields existed: drop the
|
|
161
|
-
// mandatory enum `kind`, a top-level `T | null` field, and two nested
|
|
161
|
+
// mandatory enum `kind`, a top-level `T | null` field, and two nested writeSideDef
|
|
162
162
|
// fields (a mandatory array + a `T | null`).
|
|
163
163
|
let oldJson = %raw(`function(j){
|
|
164
164
|
var c = JSON.parse(JSON.stringify(j));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Verifies that ReadModel.Spec.visibility flows through PPX injection, that the
|
|
2
2
|
// filter predicate used by Plugin_Builder.makeAutoUIManifest excludes Internal
|
|
3
3
|
// entries while leaving Public ones intact, and that Plugin_Structure.make
|
|
4
|
-
// CARRIES Internal entries but tags them via `
|
|
4
|
+
// CARRIES Internal entries but tags them via `readSideDef.visibility` (the
|
|
5
5
|
// dev-graph contract). Does NOT instantiate the full Plugin_Builder.Make functor
|
|
6
6
|
// — the filter is a pure switch on a Spec field and is therefore testable in
|
|
7
7
|
// isolation via stubbed ReadModel.T modules.
|
|
@@ -120,7 +120,7 @@ describe("ReadModel visibility filter", () => {
|
|
|
120
120
|
|
|
121
121
|
describe("Plugin_Structure.make — visibility tagging", () => {
|
|
122
122
|
// pluginStructure CARRIES Internal read models (so the dev graph / dead-code
|
|
123
|
-
// tools can see them) and tags each via `
|
|
123
|
+
// tools can see them) and tags each via `readSideDef.visibility`
|
|
124
124
|
// (`None` = Public, `Some("Internal")` = Internal). The deployed AutoUI
|
|
125
125
|
// consumers re-filter on that tag — visibility does not remove entries from
|
|
126
126
|
// pluginStructure itself. See Plugin_Structure.res / Visibility.res.
|
|
@@ -56,7 +56,7 @@ let PsGatedViewSlice_Spec = {
|
|
|
56
56
|
name: PsGatedView$ReventlessCore.name,
|
|
57
57
|
moduleUrl: PsGatedView$ReventlessCore.moduleUrl,
|
|
58
58
|
stateSchema: PsGatedView$ReventlessCore.stateSchema,
|
|
59
|
-
|
|
59
|
+
Id: {
|
|
60
60
|
schema: Id$Reventless.StringPure.schema,
|
|
61
61
|
make: prim => prim,
|
|
62
62
|
makeFromString: prim => prim,
|
|
@@ -89,7 +89,7 @@ let PsOrdersViewSlice_Spec = {
|
|
|
89
89
|
name: PsOrdersView$ReventlessCore.name,
|
|
90
90
|
moduleUrl: PsOrdersView$ReventlessCore.moduleUrl,
|
|
91
91
|
stateSchema: PsOrdersView$ReventlessCore.stateSchema,
|
|
92
|
-
|
|
92
|
+
Id: {
|
|
93
93
|
schema: Id$Reventless.StringPure.schema,
|
|
94
94
|
make: prim => prim,
|
|
95
95
|
makeFromString: prim => prim,
|
|
@@ -301,7 +301,7 @@ let structure = Plugin_Structure.make(
|
|
|
301
301
|
|
|
302
302
|
describe("lifecycle topology", () => {
|
|
303
303
|
let ordersStates = Dict.fromArray([("Orders", ["Placed", "Shipped", "Cancelled"])])
|
|
304
|
-
let writableWith = (commands): Reventless.Plugin.
|
|
304
|
+
let writableWith = (commands): Reventless.Plugin.writeSideDef => {
|
|
305
305
|
name: "Ordering",
|
|
306
306
|
commands,
|
|
307
307
|
producedEventTypes: [],
|
|
@@ -330,7 +330,7 @@ describe("lifecycle topology", () => {
|
|
|
330
330
|
testSync("names a state no command can reach", () => {
|
|
331
331
|
// `Cancelled` is in the enum and nothing declares an edge into it.
|
|
332
332
|
let findings = Plugin_Structure.lifecycleTopologyFindings(
|
|
333
|
-
~
|
|
333
|
+
~writeSides=[
|
|
334
334
|
writableWith([
|
|
335
335
|
command(~name="Ship", ~allowedStates=["Placed"], ~targetState="Shipped", ()),
|
|
336
336
|
]),
|
|
@@ -342,7 +342,7 @@ describe("lifecycle topology", () => {
|
|
|
342
342
|
|
|
343
343
|
testSync("says nothing when every state is reachable", () => {
|
|
344
344
|
let findings = Plugin_Structure.lifecycleTopologyFindings(
|
|
345
|
-
~
|
|
345
|
+
~writeSides=[
|
|
346
346
|
writableWith([
|
|
347
347
|
command(~name="Ship", ~allowedStates=["Placed"], ~targetState="Shipped", ()),
|
|
348
348
|
command(~name="Cancel", ~allowedStates=["Placed"], ~targetState="Cancelled", ()),
|
|
@@ -357,7 +357,7 @@ describe("lifecycle topology", () => {
|
|
|
357
357
|
// expected rather than suspicious.
|
|
358
358
|
testSync("does not call the initial state unreachable", () => {
|
|
359
359
|
let findings = Plugin_Structure.lifecycleTopologyFindings(
|
|
360
|
-
~
|
|
360
|
+
~writeSides=[
|
|
361
361
|
writableWith([
|
|
362
362
|
command(~name="Ship", ~allowedStates=["Placed"], ~targetState="Shipped", ()),
|
|
363
363
|
command(~name="Cancel", ~allowedStates=["Placed"], ~targetState="Cancelled", ()),
|
|
@@ -374,7 +374,7 @@ describe("lifecycle topology", () => {
|
|
|
374
374
|
// silenced. See the comment in Plugin_Structure.
|
|
375
375
|
testSync("does not report a state with no way out", () => {
|
|
376
376
|
let findings = Plugin_Structure.lifecycleTopologyFindings(
|
|
377
|
-
~
|
|
377
|
+
~writeSides=[
|
|
378
378
|
writableWith([
|
|
379
379
|
command(~name="Ship", ~allowedStates=["Placed"], ~targetState="Shipped", ()),
|
|
380
380
|
command(~name="Cancel", ~allowedStates=["Placed"], ~targetState="Cancelled", ()),
|
|
@@ -1310,7 +1310,7 @@ describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1310
1310
|
// worked it out — the same declaration-vs-guess distinction `labelFieldSource`
|
|
1311
1311
|
// publishes, for the field the generated filter and order-by are built from.
|
|
1312
1312
|
describe("idField / idFieldSource — the key and its provenance", () => {
|
|
1313
|
-
let keyOf = (q: Reventless.Plugin.
|
|
1313
|
+
let keyOf = (q: Reventless.Plugin.readSideDef) => (q.idField, q.idFieldSource)
|
|
1314
1314
|
let withCategories = Plugin_Structure.make(
|
|
1315
1315
|
~name="TestPlugin",
|
|
1316
1316
|
~stateChangeSlices=[],
|
|
@@ -1738,11 +1738,11 @@ describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1738
1738
|
| None => None
|
|
1739
1739
|
}
|
|
1740
1740
|
|
|
1741
|
-
// Phase 4:
|
|
1741
|
+
// Phase 4: readSideDef.schema must carry x-reventless-* extension keys for
|
|
1742
1742
|
// annotated state types. Plugin_Structure now uses SuryToJsonSchema.deriveObjectSchema
|
|
1743
1743
|
// (annotation-aware) instead of S.toInputJSONSchemaOrThrow (metadata-blind).
|
|
1744
|
-
describe("
|
|
1745
|
-
let parseSchema = (svs: Reventless.Plugin.
|
|
1744
|
+
describe("readSideDef.schema propagates x-reventless-* annotations", () => {
|
|
1745
|
+
let parseSchema = (svs: Reventless.Plugin.readSideDef): JSON.t => svs.schema->JSON.parseOrThrow
|
|
1746
1746
|
|
|
1747
1747
|
let annotatedSchema = structure.stateViewSlices->Array.getUnsafe(3)->parseSchema
|
|
1748
1748
|
|
|
@@ -110,7 +110,7 @@ let PsOrdersViewSlice_Spec = {
|
|
|
110
110
|
name: PsOrdersView$ReventlessCore.name,
|
|
111
111
|
moduleUrl: PsOrdersView$ReventlessCore.moduleUrl,
|
|
112
112
|
stateSchema: PsOrdersView$ReventlessCore.stateSchema,
|
|
113
|
-
|
|
113
|
+
Id: {
|
|
114
114
|
schema: Id$Reventless.StringPure.schema,
|
|
115
115
|
make: prim => prim,
|
|
116
116
|
makeFromString: prim => prim,
|
|
@@ -143,7 +143,7 @@ let PsAvailableProductsViewSlice_Spec = {
|
|
|
143
143
|
name: PsAvailableProductsView$ReventlessCore.name,
|
|
144
144
|
moduleUrl: PsAvailableProductsView$ReventlessCore.moduleUrl,
|
|
145
145
|
stateSchema: PsAvailableProductsView$ReventlessCore.stateSchema,
|
|
146
|
-
|
|
146
|
+
Id: {
|
|
147
147
|
schema: Id$Reventless.StringPure.schema,
|
|
148
148
|
make: prim => prim,
|
|
149
149
|
makeFromString: prim => prim,
|
|
@@ -176,7 +176,7 @@ let PsCustomersViewSlice_Spec = {
|
|
|
176
176
|
name: PsCustomersView$ReventlessCore.name,
|
|
177
177
|
moduleUrl: PsCustomersView$ReventlessCore.moduleUrl,
|
|
178
178
|
stateSchema: PsCustomersView$ReventlessCore.stateSchema,
|
|
179
|
-
|
|
179
|
+
Id: {
|
|
180
180
|
schema: Id$Reventless.StringPure.schema,
|
|
181
181
|
make: prim => prim,
|
|
182
182
|
makeFromString: prim => prim,
|
|
@@ -209,7 +209,7 @@ let PsAnnotatedViewSlice_Spec = {
|
|
|
209
209
|
name: PsAnnotatedView$ReventlessCore.name,
|
|
210
210
|
moduleUrl: PsAnnotatedView$ReventlessCore.moduleUrl,
|
|
211
211
|
stateSchema: PsAnnotatedView$ReventlessCore.stateSchema,
|
|
212
|
-
|
|
212
|
+
Id: {
|
|
213
213
|
schema: Id$Reventless.StringPure.schema,
|
|
214
214
|
make: prim => prim,
|
|
215
215
|
makeFromString: prim => prim,
|
|
@@ -242,7 +242,7 @@ let PsCategoriesViewSlice_Spec = {
|
|
|
242
242
|
name: PsCategoriesView$ReventlessCore.name,
|
|
243
243
|
moduleUrl: PsCategoriesView$ReventlessCore.moduleUrl,
|
|
244
244
|
stateSchema: PsCategoriesView$ReventlessCore.stateSchema,
|
|
245
|
-
|
|
245
|
+
Id: {
|
|
246
246
|
schema: Id$Reventless.StringPure.schema,
|
|
247
247
|
make: prim => prim,
|
|
248
248
|
makeFromString: prim => prim,
|
|
@@ -523,7 +523,7 @@ let PsShipmentsViewSlice_Spec = {
|
|
|
523
523
|
name: PsShipmentsView$ReventlessCore.name,
|
|
524
524
|
moduleUrl: PsShipmentsView$ReventlessCore.moduleUrl,
|
|
525
525
|
stateSchema: PsShipmentsView$ReventlessCore.stateSchema,
|
|
526
|
-
|
|
526
|
+
Id: {
|
|
527
527
|
schema: Id$Reventless.StringPure.schema,
|
|
528
528
|
make: prim => prim,
|
|
529
529
|
makeFromString: prim => prim,
|
|
@@ -1567,7 +1567,7 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1567
1567
|
return obj[fieldName];
|
|
1568
1568
|
}
|
|
1569
1569
|
};
|
|
1570
|
-
globalThis.describe("
|
|
1570
|
+
globalThis.describe("readSideDef.schema propagates x-reventless-* annotations", () => {
|
|
1571
1571
|
let annotatedSchema = JSON.parse(structure.stateViewSlices[3].schema);
|
|
1572
1572
|
globalThis.test("itemId carries x-reventless-id", () => {
|
|
1573
1573
|
globalThis.expect(Stdlib_Option.flatMap(Stdlib_Option.flatMap(getPropertyOf(annotatedSchema, "itemId"), s => getProperty(s, "x-reventless-id")), Stdlib_JSON.Decode.bool)).toBe(true);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Phase 4 fixture: state-view slice with structural annotations.
|
|
2
2
|
// Used to verify Plugin_Structure.make ships x-reventless-* extension
|
|
3
|
-
// properties through
|
|
3
|
+
// properties through readSideDef.schema after swapping S.toInputJSONSchemaOrThrow
|
|
4
4
|
// for SuryToJsonSchema.deriveObjectSchema.
|
|
5
5
|
|
|
6
6
|
@@reventless.spec("AnnotatedView")
|
|
@@ -99,8 +99,6 @@ let name = "AnnotatedView";
|
|
|
99
99
|
|
|
100
100
|
let Id;
|
|
101
101
|
|
|
102
|
-
let Key;
|
|
103
|
-
|
|
104
102
|
let moduleUrl = "@reventlessdev/reventless-core/tests/plugin/StateView/PsAnnotatedView.res.mjs";
|
|
105
103
|
|
|
106
104
|
let authorization = "AllowAuthenticated";
|
|
@@ -109,11 +107,10 @@ let visibility = "Public";
|
|
|
109
107
|
|
|
110
108
|
export {
|
|
111
109
|
name,
|
|
112
|
-
Id,
|
|
113
110
|
consumedEventSchema,
|
|
114
111
|
project,
|
|
115
112
|
config,
|
|
116
|
-
|
|
113
|
+
Id,
|
|
117
114
|
subIdConfig,
|
|
118
115
|
makeId,
|
|
119
116
|
stateSchema$1 as stateSchema,
|
|
@@ -47,8 +47,6 @@ let name = "AvailableProducts";
|
|
|
47
47
|
|
|
48
48
|
let Id;
|
|
49
49
|
|
|
50
|
-
let Key;
|
|
51
|
-
|
|
52
50
|
let subIdConfig;
|
|
53
51
|
|
|
54
52
|
let moduleUrl = "@reventlessdev/reventless-core/tests/plugin/StateView/PsAvailableProductsView.res.mjs";
|
|
@@ -59,12 +57,11 @@ let visibility = "Public";
|
|
|
59
57
|
|
|
60
58
|
export {
|
|
61
59
|
name,
|
|
62
|
-
Id,
|
|
63
60
|
consumedEventSchema,
|
|
64
61
|
stateSchema,
|
|
65
62
|
project,
|
|
66
63
|
config,
|
|
67
|
-
|
|
64
|
+
Id,
|
|
68
65
|
subIdConfig,
|
|
69
66
|
moduleUrl,
|
|
70
67
|
authorization,
|
|
@@ -34,8 +34,6 @@ let name = "Categories";
|
|
|
34
34
|
|
|
35
35
|
let Id;
|
|
36
36
|
|
|
37
|
-
let Key;
|
|
38
|
-
|
|
39
37
|
let subIdConfig;
|
|
40
38
|
|
|
41
39
|
let moduleUrl = "@reventlessdev/reventless-core/tests/plugin/StateView/PsCategoriesView.res.mjs";
|
|
@@ -46,12 +44,11 @@ let visibility = "Public";
|
|
|
46
44
|
|
|
47
45
|
export {
|
|
48
46
|
name,
|
|
49
|
-
Id,
|
|
50
47
|
consumedEventSchema,
|
|
51
48
|
stateSchema,
|
|
52
49
|
project,
|
|
53
50
|
config,
|
|
54
|
-
|
|
51
|
+
Id,
|
|
55
52
|
subIdConfig,
|
|
56
53
|
moduleUrl,
|
|
57
54
|
authorization,
|
|
@@ -47,8 +47,6 @@ let name = "Customers";
|
|
|
47
47
|
|
|
48
48
|
let Id;
|
|
49
49
|
|
|
50
|
-
let Key;
|
|
51
|
-
|
|
52
50
|
let subIdConfig;
|
|
53
51
|
|
|
54
52
|
let moduleUrl = "@reventlessdev/reventless-core/tests/plugin/StateView/PsCustomersView.res.mjs";
|
|
@@ -59,12 +57,11 @@ let visibility = "Public";
|
|
|
59
57
|
|
|
60
58
|
export {
|
|
61
59
|
name,
|
|
62
|
-
Id,
|
|
63
60
|
consumedEventSchema,
|
|
64
61
|
stateSchema$1 as stateSchema,
|
|
65
62
|
project,
|
|
66
63
|
config,
|
|
67
|
-
|
|
64
|
+
Id,
|
|
68
65
|
subIdConfig,
|
|
69
66
|
moduleUrl,
|
|
70
67
|
authorization,
|