@reventlessdev/reventless-core 3.0.0-alpha.250 → 3.0.0-alpha.252
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 +40 -0
- package/package.json +7 -7
- package/src/admin/Platform_Admin_Structure.res +4 -1
- package/src/admin/Platform_Admin_Structure.res.mjs +4 -2
- package/src/admin/Platform_BakedManifest.res.mjs +3 -1
- package/src/admin/Platform_ComponentDefinitionsApi.res +31 -1
- package/src/admin/Platform_ComponentDefinitionsApi.res.mjs +29 -1
- package/src/admin/Platform_PluginStructuresApi.res +80 -8
- package/src/admin/Platform_PluginStructuresApi.res.mjs +76 -2
- package/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs +8 -0
- package/src/components/Api/ApiNoApiHelpers.res +37 -3
- package/src/components/Api/ApiNoApiHelpers.res.mjs +29 -2
- package/src/components/AutomationSlice/AutomationSlice_Callback.res +4 -4
- package/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs +3 -3
- package/src/plugin/api/PluginBaseFragment.res +3 -3
- package/src/plugin/component/Plugin_Structure.res +787 -384
- package/src/plugin/component/Plugin_Structure.res.mjs +430 -20
- package/src/plugin/connect/PluginConnectExtension_Mapping.res +3 -6
- package/src/plugin/connect/PluginConnectExtension_Mapping.res.mjs +14 -2
- package/src/plugin/connect/PluginExtensionPoint_Plugin.res +0 -1
- package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +63 -3
- package/src/plugin/connect/PluginExtensionPoint_UiFragment.res.mjs +22 -3
- package/src/plugin/lifecycle/PluginBehavior.res +11 -11
- package/src/plugin/lifecycle/PluginBehavior.res.mjs +11 -11
- package/src/plugin/lifecycle/PluginSpec.res +11 -3
- package/src/plugin/lifecycle/PluginSpec.res.mjs +11 -3
- package/tests/admin/AdminApiSchemaDriftTest.res +486 -0
- package/tests/admin/AdminApiSchemaDriftTest.res.mjs +619 -0
- package/tests/admin/Platform_Admin_StructureTest.res +8 -3
- package/tests/admin/Platform_Admin_StructureTest.res.mjs +8 -2
- package/tests/admin/Platform_BakedManifestTest.res +2 -0
- package/tests/admin/Platform_BakedManifestTest.res.mjs +3 -1
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +10 -0
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +30 -8
- package/tests/admin/Platform_PluginStructuresApiTest.res +28 -1
- package/tests/admin/Platform_PluginStructuresApiTest.res.mjs +27 -5
- package/tests/aggregate/AggregateCacheTest.res.mjs +15 -3
- package/tests/aggregate/AggregateConflictTest.res.mjs +15 -3
- package/tests/aggregate/AggregateFixtures.res.mjs +15 -3
- package/tests/aggregate/AggregateSnapshotTest.res.mjs +21 -5
- package/tests/api/ApiNoApiTest.res +46 -0
- package/tests/api/ApiNoApiTest.res.mjs +49 -1
- package/tests/api/GraphQL_FragmentGeneratorTest.res.mjs +27 -3
- package/tests/commandgenerator/CommandGeneratorFixtures.res.mjs +12 -2
- package/tests/commandtopic/CommandOutcomeHookTest.res.mjs +2 -0
- package/tests/commandtopic/CommandTopicCallbackFixtures.res.mjs +12 -2
- package/tests/dcb/DcbFixtures.res.mjs +8 -0
- package/tests/dcb/DcbStateChangeSliceTest.res.mjs +18 -0
- package/tests/eventmapper/EventMapperFixtures.res.mjs +15 -3
- package/tests/extensionpoint/ExtensionPointFixtures.res.mjs +9 -1
- package/tests/extensionpoint/ExtensionPointOperationsTest.res.mjs +9 -1
- package/tests/message/MessageTest.res +2 -0
- package/tests/message/MessageTest.res.mjs +3 -1
- package/tests/plugin/PluginStructureAccessTest.res.mjs +2 -0
- package/tests/plugin/PluginStructureTest.res +294 -1
- package/tests/plugin/PluginStructureTest.res.mjs +373 -3
- package/tests/plugin/StateChangeSlice/PsAttachInvoice.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsChangePhoto.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsDispatchShipment.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsGatedCommands.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsPlaceOrder.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsReserveStock.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsShipOrder.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsTransitionSwitch.res +59 -0
- package/tests/plugin/StateChangeSlice/PsTransitionSwitch.res.mjs +115 -0
- package/tests/plugin/StateChangeSlice/PsTypoStore.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsUploadAvatar.res.mjs +8 -0
- package/tests/plugin/StateChangeSlice/PsUploadImages.res.mjs +8 -0
- package/tests/plugin/pluginDefinitionRequiredScalars.txt +26 -0
- package/tests/util/CommandPublisherTest.res.mjs +9 -1
|
@@ -94,11 +94,19 @@ let structure: pluginStructure = {
|
|
|
94
94
|
delegateNames: ["onAdded"],
|
|
95
95
|
eventTypes: ["ProductAdded"],
|
|
96
96
|
commandTypes: [],
|
|
97
|
+
handledEvents: Some([
|
|
98
|
+
{name: "Catalog.Products.ProductAdded", toCommandTypes: ["Catalog.Watch"]},
|
|
99
|
+
]),
|
|
100
|
+
issuedCommands: Some([
|
|
101
|
+
{name: "Catalog.Products.Acknowledge", fromEventTypes: ["Catalog.Watched"]},
|
|
102
|
+
]),
|
|
97
103
|
},
|
|
98
104
|
],
|
|
99
105
|
extensionPoints: None,
|
|
100
106
|
requiredStores: None,
|
|
101
107
|
requiredStoreDeclarations: None,
|
|
108
|
+
requiredCapabilities: None,
|
|
109
|
+
traitDeclarations: None,
|
|
102
110
|
}
|
|
103
111
|
|
|
104
112
|
let encoded = Platform_ComponentDefinitionsApi.encodePluginStructureEntry(
|
|
@@ -396,6 +404,8 @@ describe("allowedStates + lifecycleField populated", () => {
|
|
|
396
404
|
extensionPoints: None,
|
|
397
405
|
requiredStores: None,
|
|
398
406
|
requiredStoreDeclarations: None,
|
|
407
|
+
requiredCapabilities: None,
|
|
408
|
+
traitDeclarations: None,
|
|
399
409
|
}
|
|
400
410
|
|
|
401
411
|
let json =
|
|
@@ -133,7 +133,15 @@ let structure_extensions = [{
|
|
|
133
133
|
name: "Catalog.Products.Watcher",
|
|
134
134
|
delegateNames: ["onAdded"],
|
|
135
135
|
eventTypes: ["ProductAdded"],
|
|
136
|
-
commandTypes: []
|
|
136
|
+
commandTypes: [],
|
|
137
|
+
handledEvents: [{
|
|
138
|
+
name: "Catalog.Products.ProductAdded",
|
|
139
|
+
toCommandTypes: ["Catalog.Watch"]
|
|
140
|
+
}],
|
|
141
|
+
issuedCommands: [{
|
|
142
|
+
name: "Catalog.Products.Acknowledge",
|
|
143
|
+
fromEventTypes: ["Catalog.Watched"]
|
|
144
|
+
}]
|
|
137
145
|
}];
|
|
138
146
|
|
|
139
147
|
let structure = {
|
|
@@ -147,7 +155,9 @@ let structure = {
|
|
|
147
155
|
extensions: structure_extensions,
|
|
148
156
|
extensionPoints: undefined,
|
|
149
157
|
requiredStores: undefined,
|
|
150
|
-
requiredStoreDeclarations: undefined
|
|
158
|
+
requiredStoreDeclarations: undefined,
|
|
159
|
+
requiredCapabilities: undefined,
|
|
160
|
+
traitDeclarations: undefined
|
|
151
161
|
};
|
|
152
162
|
|
|
153
163
|
let encoded = Platform_ComponentDefinitionsApi$ReventlessCore.encodePluginStructureEntry("Catalog", undefined, structure);
|
|
@@ -256,7 +266,9 @@ globalThis.describe("translation-slice externalSystem round-trip", () => {
|
|
|
256
266
|
extensions: externalStructure_extensions,
|
|
257
267
|
extensionPoints: undefined,
|
|
258
268
|
requiredStores: undefined,
|
|
259
|
-
requiredStoreDeclarations: undefined
|
|
269
|
+
requiredStoreDeclarations: undefined,
|
|
270
|
+
requiredCapabilities: undefined,
|
|
271
|
+
traitDeclarations: undefined
|
|
260
272
|
};
|
|
261
273
|
let externalJson = JSON.stringify(Platform_ComponentDefinitionsApi$ReventlessCore.encodePluginStructureEntry("Catalog", undefined, externalStructure));
|
|
262
274
|
globalThis.test("surfaces Some outbound externalSystem as its inner string", () => {
|
|
@@ -348,7 +360,9 @@ globalThis.describe("visibility filtering (deployed AutoUI hides Internal)", ()
|
|
|
348
360
|
extensions: mixed_extensions,
|
|
349
361
|
extensionPoints: undefined,
|
|
350
362
|
requiredStores: undefined,
|
|
351
|
-
requiredStoreDeclarations: undefined
|
|
363
|
+
requiredStoreDeclarations: undefined,
|
|
364
|
+
requiredCapabilities: undefined,
|
|
365
|
+
traitDeclarations: undefined
|
|
352
366
|
};
|
|
353
367
|
let mixedEntry = Platform_ComponentDefinitionsApi$ReventlessCore.encodePluginStructureEntry("Ordering", undefined, mixed);
|
|
354
368
|
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));
|
|
@@ -377,7 +391,9 @@ globalThis.describe("visibility filtering (deployed AutoUI hides Internal)", ()
|
|
|
377
391
|
extensions: structure_extensions,
|
|
378
392
|
extensionPoints: undefined,
|
|
379
393
|
requiredStores: undefined,
|
|
380
|
-
requiredStoreDeclarations: undefined
|
|
394
|
+
requiredStoreDeclarations: undefined,
|
|
395
|
+
requiredCapabilities: undefined,
|
|
396
|
+
traitDeclarations: undefined
|
|
381
397
|
});
|
|
382
398
|
globalThis.expect(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(entry), o => o["internalQueryables"])).toEqual([]);
|
|
383
399
|
});
|
|
@@ -469,7 +485,9 @@ globalThis.describe("allowedStates + lifecycleField populated", () => {
|
|
|
469
485
|
extensions: structureWithStates_extensions,
|
|
470
486
|
extensionPoints: undefined,
|
|
471
487
|
requiredStores: undefined,
|
|
472
|
-
requiredStoreDeclarations: undefined
|
|
488
|
+
requiredStoreDeclarations: undefined,
|
|
489
|
+
requiredCapabilities: undefined,
|
|
490
|
+
traitDeclarations: undefined
|
|
473
491
|
};
|
|
474
492
|
let json = JSON.stringify(Platform_ComponentDefinitionsApi$ReventlessCore.encodePluginStructureEntry("Platform", undefined, structureWithStates));
|
|
475
493
|
globalThis.test("encodes populated allowedStates as a JSON array", () => {
|
|
@@ -524,7 +542,9 @@ globalThis.describe("singleQueryField reaches the caller", () => {
|
|
|
524
542
|
extensions: structure_extensions,
|
|
525
543
|
extensionPoints: undefined,
|
|
526
544
|
requiredStores: undefined,
|
|
527
|
-
requiredStoreDeclarations: undefined
|
|
545
|
+
requiredStoreDeclarations: undefined,
|
|
546
|
+
requiredCapabilities: undefined,
|
|
547
|
+
traitDeclarations: undefined
|
|
528
548
|
}));
|
|
529
549
|
globalThis.expect(unstated.includes("\"singleQueryField\":null")).toEqual(true);
|
|
530
550
|
});
|
|
@@ -572,7 +592,9 @@ globalThis.describe("idField / idFieldSource reach the caller", () => {
|
|
|
572
592
|
extensions: structure_extensions,
|
|
573
593
|
extensionPoints: undefined,
|
|
574
594
|
requiredStores: undefined,
|
|
575
|
-
requiredStoreDeclarations: undefined
|
|
595
|
+
requiredStoreDeclarations: undefined,
|
|
596
|
+
requiredCapabilities: undefined,
|
|
597
|
+
traitDeclarations: undefined
|
|
576
598
|
}));
|
|
577
599
|
globalThis.expect(unresolved.includes("\"idField\":null")).toEqual(true);
|
|
578
600
|
globalThis.expect(unresolved.includes("\"idFieldSource\":null")).toEqual(true);
|
|
@@ -52,12 +52,23 @@ let structure: pluginStructure = {
|
|
|
52
52
|
delegateNames: ["onAdded"],
|
|
53
53
|
sourceEventTypes: ["Catalog.ProductAdded"],
|
|
54
54
|
commandTypes: None,
|
|
55
|
+
publishedEvents: Some([
|
|
56
|
+
{
|
|
57
|
+
name: "Catalog.Products.ProductBecameAvailable",
|
|
58
|
+
fromEventTypes: ["Catalog.ProductAdded"],
|
|
59
|
+
},
|
|
60
|
+
]),
|
|
61
|
+
acceptedCommands: Some([
|
|
62
|
+
{name: "Catalog.Products.Reserve", toCommandTypes: ["Catalog.ReserveStock"]},
|
|
63
|
+
]),
|
|
55
64
|
},
|
|
56
65
|
]),
|
|
57
66
|
requiredStores: Some(["Catalog.images"]),
|
|
58
67
|
requiredStoreDeclarations: Some([
|
|
59
68
|
{store: "Catalog.images", component: "Product", field: "image", annotation: Some("images")},
|
|
60
69
|
]),
|
|
70
|
+
requiredCapabilities: Some([{capability: "Geocoding", component: "GeocodeAddress"}]),
|
|
71
|
+
traitDeclarations: None,
|
|
61
72
|
}
|
|
62
73
|
|
|
63
74
|
let encoded = Platform_PluginStructuresApi.encodePluginStructureEntry(
|
|
@@ -89,10 +100,12 @@ describe("Platform_PluginStructures entry", () => {
|
|
|
89
100
|
"outboundTranslationSlices",
|
|
90
101
|
"pluginId",
|
|
91
102
|
"readModels",
|
|
103
|
+
"requiredCapabilities",
|
|
92
104
|
"requiredStoreDeclarations",
|
|
93
105
|
"requiredStores",
|
|
94
106
|
"stateChangeSlices",
|
|
95
107
|
"stateViewSlices",
|
|
108
|
+
"traitDeclarations",
|
|
96
109
|
])
|
|
97
110
|
})
|
|
98
111
|
|
|
@@ -116,7 +129,9 @@ describe("Platform_PluginStructures entry", () => {
|
|
|
116
129
|
testSync("encodes extension points with their source event types", () =>
|
|
117
130
|
expect(
|
|
118
131
|
json->String.includes(
|
|
119
|
-
"\"extensionPoints\":[{\"name\":\"Catalog.Products\",\"delegateNames\":[\"onAdded\"],\"sourceEventTypes\":[\"Catalog.ProductAdded\"],\"commandTypes\":null
|
|
132
|
+
"\"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\"]}]}]",
|
|
120
135
|
),
|
|
121
136
|
)->toEqual(true)
|
|
122
137
|
)
|
|
@@ -131,6 +146,16 @@ describe("Platform_PluginStructures entry", () => {
|
|
|
131
146
|
testSync("encodes required stores with their provenance", () =>
|
|
132
147
|
expect(json->String.includes("\"requiredStores\":[\"Catalog.images\"]"))->toEqual(true)
|
|
133
148
|
)
|
|
149
|
+
|
|
150
|
+
// No `field`: a capability a slice declares is not a field's need, which is why
|
|
151
|
+
// it travels beside `requiredStores` rather than inside it.
|
|
152
|
+
testSync("encodes required capabilities with their declaring component", () =>
|
|
153
|
+
expect(
|
|
154
|
+
json->String.includes(
|
|
155
|
+
"\"requiredCapabilities\":[{\"capability\":\"Geocoding\",\"component\":\"GeocodeAddress\"}]",
|
|
156
|
+
),
|
|
157
|
+
)->toEqual(true)
|
|
158
|
+
)
|
|
134
159
|
})
|
|
135
160
|
|
|
136
161
|
// A structure persisted before these fields existed decodes as None, and null is the
|
|
@@ -142,6 +167,8 @@ describe("absent optional collections", () => {
|
|
|
142
167
|
extensionPoints: None,
|
|
143
168
|
requiredStores: None,
|
|
144
169
|
requiredStoreDeclarations: None,
|
|
170
|
+
requiredCapabilities: None,
|
|
171
|
+
traitDeclarations: None,
|
|
145
172
|
}
|
|
146
173
|
let bareJson =
|
|
147
174
|
Platform_PluginStructuresApi.encodePluginStructureEntry(
|
|
@@ -107,7 +107,15 @@ let structure_extensionPoints = [{
|
|
|
107
107
|
name: "Catalog.Products",
|
|
108
108
|
delegateNames: ["onAdded"],
|
|
109
109
|
sourceEventTypes: ["Catalog.ProductAdded"],
|
|
110
|
-
commandTypes: undefined
|
|
110
|
+
commandTypes: undefined,
|
|
111
|
+
publishedEvents: [{
|
|
112
|
+
name: "Catalog.Products.ProductBecameAvailable",
|
|
113
|
+
fromEventTypes: ["Catalog.ProductAdded"]
|
|
114
|
+
}],
|
|
115
|
+
acceptedCommands: [{
|
|
116
|
+
name: "Catalog.Products.Reserve",
|
|
117
|
+
toCommandTypes: ["Catalog.ReserveStock"]
|
|
118
|
+
}]
|
|
111
119
|
}];
|
|
112
120
|
|
|
113
121
|
let structure_requiredStores = ["Catalog.images"];
|
|
@@ -119,6 +127,11 @@ let structure_requiredStoreDeclarations = [{
|
|
|
119
127
|
annotation: "images"
|
|
120
128
|
}];
|
|
121
129
|
|
|
130
|
+
let structure_requiredCapabilities = [{
|
|
131
|
+
capability: "Geocoding",
|
|
132
|
+
component: "GeocodeAddress"
|
|
133
|
+
}];
|
|
134
|
+
|
|
122
135
|
let structure = {
|
|
123
136
|
readModels: structure_readModels,
|
|
124
137
|
stateViewSlices: structure_stateViewSlices,
|
|
@@ -130,7 +143,9 @@ let structure = {
|
|
|
130
143
|
extensions: structure_extensions,
|
|
131
144
|
extensionPoints: structure_extensionPoints,
|
|
132
145
|
requiredStores: structure_requiredStores,
|
|
133
|
-
requiredStoreDeclarations: structure_requiredStoreDeclarations
|
|
146
|
+
requiredStoreDeclarations: structure_requiredStoreDeclarations,
|
|
147
|
+
requiredCapabilities: structure_requiredCapabilities,
|
|
148
|
+
traitDeclarations: undefined
|
|
134
149
|
};
|
|
135
150
|
|
|
136
151
|
let encoded = Platform_PluginStructuresApi$ReventlessCore.encodePluginStructureEntry("Catalog", structure);
|
|
@@ -154,10 +169,12 @@ globalThis.describe("Platform_PluginStructures entry", () => {
|
|
|
154
169
|
"outboundTranslationSlices",
|
|
155
170
|
"pluginId",
|
|
156
171
|
"readModels",
|
|
172
|
+
"requiredCapabilities",
|
|
157
173
|
"requiredStoreDeclarations",
|
|
158
174
|
"requiredStores",
|
|
159
175
|
"stateChangeSlices",
|
|
160
|
-
"stateViewSlices"
|
|
176
|
+
"stateViewSlices",
|
|
177
|
+
"traitDeclarations"
|
|
161
178
|
]);
|
|
162
179
|
});
|
|
163
180
|
globalThis.test("keeps Internal read models", () => {
|
|
@@ -176,7 +193,7 @@ globalThis.describe("Platform_PluginStructures entry", () => {
|
|
|
176
193
|
globalThis.expect(json.includes("\"chapter\":\"Inventory\"")).toEqual(true);
|
|
177
194
|
});
|
|
178
195
|
globalThis.test("encodes extension points with their source event types", () => {
|
|
179
|
-
globalThis.expect(json.includes("\"extensionPoints\":[{\"name\":\"Catalog.Products\",\"delegateNames\":[\"onAdded\"],\"sourceEventTypes\":[\"Catalog.ProductAdded\"],\"commandTypes\":null}]")).toEqual(true);
|
|
196
|
+
globalThis.expect(json.includes("\"extensionPoints\":[{\"name\":\"Catalog.Products\",\"delegateNames\":[\"onAdded\"],\"sourceEventTypes\":[\"Catalog.ProductAdded\"],\"commandTypes\":null,\"publishedEvents\":[{\"name\":\"Catalog.Products.ProductBecameAvailable\",\"fromEventTypes\":[\"Catalog.ProductAdded\"]}],\"acceptedCommands\":[{\"name\":\"Catalog.Products.Reserve\",\"toCommandTypes\":[\"Catalog.ReserveStock\"]}]}]")).toEqual(true);
|
|
180
197
|
});
|
|
181
198
|
globalThis.test("encodes the singular query field beside the list one", () => {
|
|
182
199
|
globalThis.expect(json.includes("\"singleQueryField\":\"Catalog_Product\"")).toEqual(true);
|
|
@@ -184,6 +201,9 @@ globalThis.describe("Platform_PluginStructures entry", () => {
|
|
|
184
201
|
globalThis.test("encodes required stores with their provenance", () => {
|
|
185
202
|
globalThis.expect(json.includes("\"requiredStores\":[\"Catalog.images\"]")).toEqual(true);
|
|
186
203
|
});
|
|
204
|
+
globalThis.test("encodes required capabilities with their declaring component", () => {
|
|
205
|
+
globalThis.expect(json.includes("\"requiredCapabilities\":[{\"capability\":\"Geocoding\",\"component\":\"GeocodeAddress\"}]")).toEqual(true);
|
|
206
|
+
});
|
|
187
207
|
});
|
|
188
208
|
|
|
189
209
|
globalThis.describe("absent optional collections", () => {
|
|
@@ -206,7 +226,9 @@ globalThis.describe("absent optional collections", () => {
|
|
|
206
226
|
extensions: bare_extensions,
|
|
207
227
|
extensionPoints: undefined,
|
|
208
228
|
requiredStores: undefined,
|
|
209
|
-
requiredStoreDeclarations: undefined
|
|
229
|
+
requiredStoreDeclarations: undefined,
|
|
230
|
+
requiredCapabilities: undefined,
|
|
231
|
+
traitDeclarations: undefined
|
|
210
232
|
};
|
|
211
233
|
let bareJson = JSON.stringify(Platform_PluginStructuresApi$ReventlessCore.encodePluginStructureEntry("Catalog", bare));
|
|
212
234
|
globalThis.test("encodes absent extensionPoints as null", () => {
|
|
@@ -37,6 +37,12 @@ function commandAuthorization(param) {
|
|
|
37
37
|
return "AllowAuthenticated";
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
function commandTransition(param) {
|
|
41
|
+
return "Unrestricted";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let traits = [];
|
|
45
|
+
|
|
40
46
|
let AggSpec = {
|
|
41
47
|
Id: undefined,
|
|
42
48
|
name: name,
|
|
@@ -44,7 +50,9 @@ let AggSpec = {
|
|
|
44
50
|
eventSchema: eventSchema,
|
|
45
51
|
errorSchema: errorSchema,
|
|
46
52
|
moduleUrl: moduleUrl,
|
|
47
|
-
commandAuthorization: commandAuthorization
|
|
53
|
+
commandAuthorization: commandAuthorization,
|
|
54
|
+
commandTransition: commandTransition,
|
|
55
|
+
traits: traits
|
|
48
56
|
};
|
|
49
57
|
|
|
50
58
|
let initialState = {
|
|
@@ -237,7 +245,9 @@ let TestHandler = Aggregate_Callback$ReventlessCore.Make({
|
|
|
237
245
|
errorSchema: errorSchema,
|
|
238
246
|
commandSchema: commandSchema,
|
|
239
247
|
moduleUrl: moduleUrl,
|
|
240
|
-
commandAuthorization: commandAuthorization
|
|
248
|
+
commandAuthorization: commandAuthorization,
|
|
249
|
+
commandTransition: commandTransition,
|
|
250
|
+
traits: traits
|
|
241
251
|
})({
|
|
242
252
|
initialState: initialState,
|
|
243
253
|
evolve: evolve,
|
|
@@ -258,7 +268,9 @@ let TestHandler = Aggregate_Callback$ReventlessCore.Make({
|
|
|
258
268
|
errorSchema: errorSchema,
|
|
259
269
|
commandSchema: commandSchema,
|
|
260
270
|
moduleUrl: moduleUrl,
|
|
261
|
-
commandAuthorization: commandAuthorization
|
|
271
|
+
commandAuthorization: commandAuthorization,
|
|
272
|
+
commandTransition: commandTransition,
|
|
273
|
+
traits: traits
|
|
262
274
|
},
|
|
263
275
|
EventLog: {
|
|
264
276
|
Spec: {
|
|
@@ -26,6 +26,12 @@ function commandAuthorization(param) {
|
|
|
26
26
|
return "AllowAuthenticated";
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
function commandTransition(param) {
|
|
30
|
+
return "Unrestricted";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let traits = [];
|
|
34
|
+
|
|
29
35
|
let AggSpec = {
|
|
30
36
|
Id: undefined,
|
|
31
37
|
name: name,
|
|
@@ -33,7 +39,9 @@ let AggSpec = {
|
|
|
33
39
|
eventSchema: eventSchema,
|
|
34
40
|
errorSchema: errorSchema,
|
|
35
41
|
moduleUrl: moduleUrl,
|
|
36
|
-
commandAuthorization: commandAuthorization
|
|
42
|
+
commandAuthorization: commandAuthorization,
|
|
43
|
+
commandTransition: commandTransition,
|
|
44
|
+
traits: traits
|
|
37
45
|
};
|
|
38
46
|
|
|
39
47
|
let initialState = {
|
|
@@ -194,7 +202,9 @@ let TestHandler = Aggregate_Callback$ReventlessCore.Make({
|
|
|
194
202
|
errorSchema: errorSchema,
|
|
195
203
|
commandSchema: commandSchema,
|
|
196
204
|
moduleUrl: moduleUrl,
|
|
197
|
-
commandAuthorization: commandAuthorization
|
|
205
|
+
commandAuthorization: commandAuthorization,
|
|
206
|
+
commandTransition: commandTransition,
|
|
207
|
+
traits: traits
|
|
198
208
|
})({
|
|
199
209
|
initialState: initialState,
|
|
200
210
|
evolve: evolve,
|
|
@@ -215,7 +225,9 @@ let TestHandler = Aggregate_Callback$ReventlessCore.Make({
|
|
|
215
225
|
errorSchema: errorSchema,
|
|
216
226
|
commandSchema: commandSchema,
|
|
217
227
|
moduleUrl: moduleUrl,
|
|
218
|
-
commandAuthorization: commandAuthorization
|
|
228
|
+
commandAuthorization: commandAuthorization,
|
|
229
|
+
commandTransition: commandTransition,
|
|
230
|
+
traits: traits
|
|
219
231
|
},
|
|
220
232
|
EventLog: {
|
|
221
233
|
Spec: {
|
|
@@ -40,6 +40,12 @@ function commandAuthorization(param) {
|
|
|
40
40
|
return "AllowAuthenticated";
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
function commandTransition(param) {
|
|
44
|
+
return "Unrestricted";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let traits = [];
|
|
48
|
+
|
|
43
49
|
let AggSpec = {
|
|
44
50
|
Id: undefined,
|
|
45
51
|
name: name,
|
|
@@ -47,7 +53,9 @@ let AggSpec = {
|
|
|
47
53
|
eventSchema: eventSchema,
|
|
48
54
|
errorSchema: errorSchema,
|
|
49
55
|
moduleUrl: moduleUrl,
|
|
50
|
-
commandAuthorization: commandAuthorization
|
|
56
|
+
commandAuthorization: commandAuthorization,
|
|
57
|
+
commandTransition: commandTransition,
|
|
58
|
+
traits: traits
|
|
51
59
|
};
|
|
52
60
|
|
|
53
61
|
let stateSchema = Sury.union([
|
|
@@ -229,7 +237,9 @@ let TestHandler = Aggregate_Callback$ReventlessCore.Make({
|
|
|
229
237
|
errorSchema: errorSchema,
|
|
230
238
|
commandSchema: commandSchema,
|
|
231
239
|
moduleUrl: moduleUrl,
|
|
232
|
-
commandAuthorization: commandAuthorization
|
|
240
|
+
commandAuthorization: commandAuthorization,
|
|
241
|
+
commandTransition: commandTransition,
|
|
242
|
+
traits: traits
|
|
233
243
|
})({
|
|
234
244
|
initialState: "NotCreated",
|
|
235
245
|
evolve: evolve,
|
|
@@ -250,7 +260,9 @@ let TestHandler = Aggregate_Callback$ReventlessCore.Make({
|
|
|
250
260
|
errorSchema: errorSchema,
|
|
251
261
|
commandSchema: commandSchema,
|
|
252
262
|
moduleUrl: moduleUrl,
|
|
253
|
-
commandAuthorization: commandAuthorization
|
|
263
|
+
commandAuthorization: commandAuthorization,
|
|
264
|
+
commandTransition: commandTransition,
|
|
265
|
+
traits: traits
|
|
254
266
|
},
|
|
255
267
|
EventLog: {
|
|
256
268
|
Spec: {
|
|
@@ -32,6 +32,12 @@ function commandAuthorization(param) {
|
|
|
32
32
|
return "AllowAuthenticated";
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function commandTransition(param) {
|
|
36
|
+
return "Unrestricted";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let traits = [];
|
|
40
|
+
|
|
35
41
|
let AggSpec = {
|
|
36
42
|
Id: undefined,
|
|
37
43
|
name: name,
|
|
@@ -39,7 +45,9 @@ let AggSpec = {
|
|
|
39
45
|
eventSchema: eventSchema,
|
|
40
46
|
errorSchema: errorSchema,
|
|
41
47
|
moduleUrl: moduleUrl,
|
|
42
|
-
commandAuthorization: commandAuthorization
|
|
48
|
+
commandAuthorization: commandAuthorization,
|
|
49
|
+
commandTransition: commandTransition,
|
|
50
|
+
traits: traits
|
|
43
51
|
};
|
|
44
52
|
|
|
45
53
|
let stateSchema = Sury.$schema(s => ({
|
|
@@ -284,7 +292,9 @@ let TestHandler = Aggregate_Callback$ReventlessCore.Make({
|
|
|
284
292
|
errorSchema: errorSchema,
|
|
285
293
|
commandSchema: commandSchema,
|
|
286
294
|
moduleUrl: moduleUrl,
|
|
287
|
-
commandAuthorization: commandAuthorization
|
|
295
|
+
commandAuthorization: commandAuthorization,
|
|
296
|
+
commandTransition: commandTransition,
|
|
297
|
+
traits: traits
|
|
288
298
|
})({
|
|
289
299
|
initialState: initialState,
|
|
290
300
|
evolve: evolve,
|
|
@@ -305,7 +315,9 @@ let TestHandler = Aggregate_Callback$ReventlessCore.Make({
|
|
|
305
315
|
errorSchema: errorSchema,
|
|
306
316
|
commandSchema: commandSchema,
|
|
307
317
|
moduleUrl: moduleUrl,
|
|
308
|
-
commandAuthorization: commandAuthorization
|
|
318
|
+
commandAuthorization: commandAuthorization,
|
|
319
|
+
commandTransition: commandTransition,
|
|
320
|
+
traits: traits
|
|
309
321
|
},
|
|
310
322
|
EventLog: {
|
|
311
323
|
Spec: {
|
|
@@ -426,7 +438,9 @@ let PlainHandler = Aggregate_Callback$ReventlessCore.Make({
|
|
|
426
438
|
errorSchema: errorSchema,
|
|
427
439
|
commandSchema: commandSchema,
|
|
428
440
|
moduleUrl: moduleUrl,
|
|
429
|
-
commandAuthorization: commandAuthorization
|
|
441
|
+
commandAuthorization: commandAuthorization,
|
|
442
|
+
commandTransition: commandTransition,
|
|
443
|
+
traits: traits
|
|
430
444
|
})({
|
|
431
445
|
initialState: initialState$1,
|
|
432
446
|
evolve: evolve$1,
|
|
@@ -447,7 +461,9 @@ let PlainHandler = Aggregate_Callback$ReventlessCore.Make({
|
|
|
447
461
|
errorSchema: errorSchema,
|
|
448
462
|
commandSchema: commandSchema,
|
|
449
463
|
moduleUrl: moduleUrl,
|
|
450
|
-
commandAuthorization: commandAuthorization
|
|
464
|
+
commandAuthorization: commandAuthorization,
|
|
465
|
+
commandTransition: commandTransition,
|
|
466
|
+
traits: traits
|
|
451
467
|
},
|
|
452
468
|
EventLog: {
|
|
453
469
|
Spec: {
|
|
@@ -1,6 +1,52 @@
|
|
|
1
1
|
open JestGlobals
|
|
2
2
|
open ApiNoApiHelpers
|
|
3
3
|
|
|
4
|
+
// The exclusion has to survive a variant spread. Splicing copies a union's
|
|
5
|
+
// members, not its metadata, so an exclusion recorded only on the union vanishes
|
|
6
|
+
// on the way into the host — and the host publishes as a mutation and a
|
|
7
|
+
// subscription a command whose author marked it internal. No error, no warning.
|
|
8
|
+
//
|
|
9
|
+
// Built the way the PPX builds it (`markNoApiVariants` on a freshly made union),
|
|
10
|
+
// then spliced the way the compiler splices it (concatenating `anyOf`), so this
|
|
11
|
+
// exercises the real path rather than a hand-stamped stand-in.
|
|
12
|
+
let member = name =>
|
|
13
|
+
S.object(o => {
|
|
14
|
+
let _ = o.field("TAG", S.literal(name))
|
|
15
|
+
})->S.castToUnknown
|
|
16
|
+
|
|
17
|
+
let sourceUnion =
|
|
18
|
+
S.union([member("Public"), member("Internal")])->ReventlessInfra.Api.markNoApiVariants([
|
|
19
|
+
"Internal",
|
|
20
|
+
])
|
|
21
|
+
|
|
22
|
+
let spliced = switch sourceUnion {
|
|
23
|
+
| AnyOf({anyOf}) => S.union(Array.concat([member("HostOwn")], anyOf))
|
|
24
|
+
| _ => sourceUnion
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
describe("a spread carries its exclusions", () => {
|
|
28
|
+
testSync("the source union still reports its own exclusion", () =>
|
|
29
|
+
expect(getExcludedVariants(sourceUnion)->Option.map(Set.toArray))->toEqual(Some(["Internal"]))
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
testSync("a host that splices the members inherits the exclusion", () =>
|
|
33
|
+
expect(getExcludedVariants(spliced)->Option.map(Set.toArray))->toEqual(Some(["Internal"]))
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
// The failure this closes, stated as the thing it must not do: the spliced
|
|
37
|
+
// internal variant must not appear among the host's callable fields.
|
|
38
|
+
testSync("the spliced internal variant is filtered out of a host's fields", () =>
|
|
39
|
+
expect(filterNoApiVariants(["HostOwn", "Public", "Internal"], spliced))->toEqual([
|
|
40
|
+
"HostOwn",
|
|
41
|
+
"Public",
|
|
42
|
+
])
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
testSync("nothing else is filtered", () =>
|
|
46
|
+
expect(filterNoApiVariants(["HostOwn", "Public"], spliced))->toEqual(["HostOwn", "Public"])
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
|
|
4
50
|
describe("ApiNoApiHelpers:", () => {
|
|
5
51
|
testSync("isNoApi returns false for schema without noApi metadata", () => {
|
|
6
52
|
let schema = S.string->S.castToUnknown
|
|
@@ -5,6 +5,49 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
|
5
5
|
import * as Api$ReventlessInfra from "@reventlessdev/reventless-infra/src/components/Api.res.mjs";
|
|
6
6
|
import * as ApiNoApiHelpers$ReventlessCore from "../../src/components/Api/ApiNoApiHelpers.res.mjs";
|
|
7
7
|
|
|
8
|
+
function member(name) {
|
|
9
|
+
return Sury.object(o => {
|
|
10
|
+
o.f("TAG", Sury.literal(name));
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let sourceUnion = Api$ReventlessInfra.markNoApiVariants(Sury.union([
|
|
15
|
+
member("Public"),
|
|
16
|
+
member("Internal")
|
|
17
|
+
]), ["Internal"]);
|
|
18
|
+
|
|
19
|
+
let spliced;
|
|
20
|
+
|
|
21
|
+
spliced = sourceUnion.type === "anyOf" ? Sury.union([member("HostOwn")].concat(sourceUnion.anyOf)) : sourceUnion;
|
|
22
|
+
|
|
23
|
+
globalThis.describe("a spread carries its exclusions", () => {
|
|
24
|
+
globalThis.test("the source union still reports its own exclusion", () => {
|
|
25
|
+
globalThis.expect(Stdlib_Option.map(ApiNoApiHelpers$ReventlessCore.getExcludedVariants(sourceUnion), prim => Array.from(prim))).toEqual(["Internal"]);
|
|
26
|
+
});
|
|
27
|
+
globalThis.test("a host that splices the members inherits the exclusion", () => {
|
|
28
|
+
globalThis.expect(Stdlib_Option.map(ApiNoApiHelpers$ReventlessCore.getExcludedVariants(spliced), prim => Array.from(prim))).toEqual(["Internal"]);
|
|
29
|
+
});
|
|
30
|
+
globalThis.test("the spliced internal variant is filtered out of a host's fields", () => {
|
|
31
|
+
globalThis.expect(ApiNoApiHelpers$ReventlessCore.filterNoApiVariants([
|
|
32
|
+
"HostOwn",
|
|
33
|
+
"Public",
|
|
34
|
+
"Internal"
|
|
35
|
+
], spliced)).toEqual([
|
|
36
|
+
"HostOwn",
|
|
37
|
+
"Public"
|
|
38
|
+
]);
|
|
39
|
+
});
|
|
40
|
+
globalThis.test("nothing else is filtered", () => {
|
|
41
|
+
globalThis.expect(ApiNoApiHelpers$ReventlessCore.filterNoApiVariants([
|
|
42
|
+
"HostOwn",
|
|
43
|
+
"Public"
|
|
44
|
+
], spliced)).toEqual([
|
|
45
|
+
"HostOwn",
|
|
46
|
+
"Public"
|
|
47
|
+
]);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
8
51
|
globalThis.describe("ApiNoApiHelpers:", () => {
|
|
9
52
|
globalThis.test("isNoApi returns false for schema without noApi metadata", () => {
|
|
10
53
|
let schema = Sury.string;
|
|
@@ -95,4 +138,9 @@ globalThis.describe("ApiNoApiHelpers:", () => {
|
|
|
95
138
|
});
|
|
96
139
|
});
|
|
97
140
|
|
|
98
|
-
|
|
141
|
+
export {
|
|
142
|
+
member,
|
|
143
|
+
sourceUnion,
|
|
144
|
+
spliced,
|
|
145
|
+
}
|
|
146
|
+
/* sourceUnion Not a pure module */
|
|
@@ -24,9 +24,17 @@ function commandAuthorization(param) {
|
|
|
24
24
|
return "AllowAuthenticated";
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
function commandTransition(param) {
|
|
28
|
+
return "Unrestricted";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let traits = [];
|
|
32
|
+
|
|
27
33
|
let OrderSliceCmd = {
|
|
28
34
|
commandSchema: commandSchema,
|
|
29
|
-
commandAuthorization: commandAuthorization
|
|
35
|
+
commandAuthorization: commandAuthorization,
|
|
36
|
+
commandTransition: commandTransition,
|
|
37
|
+
traits: traits
|
|
30
38
|
};
|
|
31
39
|
|
|
32
40
|
function mutationFor(fragment, needle) {
|
|
@@ -196,9 +204,17 @@ function commandAuthorization$1(param) {
|
|
|
196
204
|
return "AllowAuthenticated";
|
|
197
205
|
}
|
|
198
206
|
|
|
207
|
+
function commandTransition$1(param) {
|
|
208
|
+
return "Unrestricted";
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let traits$1 = [];
|
|
212
|
+
|
|
199
213
|
let AddProductCmd = {
|
|
200
214
|
commandSchema: commandSchema$1,
|
|
201
|
-
commandAuthorization: commandAuthorization$1
|
|
215
|
+
commandAuthorization: commandAuthorization$1,
|
|
216
|
+
commandTransition: commandTransition$1,
|
|
217
|
+
traits: traits$1
|
|
202
218
|
};
|
|
203
219
|
|
|
204
220
|
let commandSchema$2 = Sury.union([
|
|
@@ -217,9 +233,17 @@ function commandAuthorization$2(param) {
|
|
|
217
233
|
return "AllowAuthenticated";
|
|
218
234
|
}
|
|
219
235
|
|
|
236
|
+
function commandTransition$2(param) {
|
|
237
|
+
return "Unrestricted";
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
let traits$2 = [];
|
|
241
|
+
|
|
220
242
|
let ChangePriceCmd = {
|
|
221
243
|
commandSchema: commandSchema$2,
|
|
222
|
-
commandAuthorization: commandAuthorization$2
|
|
244
|
+
commandAuthorization: commandAuthorization$2,
|
|
245
|
+
commandTransition: commandTransition$2,
|
|
246
|
+
traits: traits$2
|
|
223
247
|
};
|
|
224
248
|
|
|
225
249
|
globalThis.describe("semantic composites are named once, not once per field", () => {
|
|
@@ -32,6 +32,12 @@ function commandAuthorization(param) {
|
|
|
32
32
|
return "AllowAuthenticated";
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function commandTransition(param) {
|
|
36
|
+
return "Unrestricted";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let traits = [];
|
|
40
|
+
|
|
35
41
|
let CmdGenAggSpec = {
|
|
36
42
|
Id: undefined,
|
|
37
43
|
name: name,
|
|
@@ -39,7 +45,9 @@ let CmdGenAggSpec = {
|
|
|
39
45
|
eventSchema: eventSchema,
|
|
40
46
|
errorSchema: errorSchema,
|
|
41
47
|
moduleUrl: moduleUrl,
|
|
42
|
-
commandAuthorization: commandAuthorization
|
|
48
|
+
commandAuthorization: commandAuthorization,
|
|
49
|
+
commandTransition: commandTransition,
|
|
50
|
+
traits: traits
|
|
43
51
|
};
|
|
44
52
|
|
|
45
53
|
let moduleUrl$1 = import.meta.url;
|
|
@@ -106,7 +114,9 @@ let TestGenerator = CommandGenerator_Callback$ReventlessCore.Make(MockPublishSpe
|
|
|
106
114
|
errorSchema: errorSchema,
|
|
107
115
|
commandSchema: commandSchema,
|
|
108
116
|
moduleUrl: moduleUrl,
|
|
109
|
-
commandAuthorization: commandAuthorization
|
|
117
|
+
commandAuthorization: commandAuthorization,
|
|
118
|
+
commandTransition: commandTransition,
|
|
119
|
+
traits: traits
|
|
110
120
|
});
|
|
111
121
|
|
|
112
122
|
let singleTagCommandSchema = Sury.$schema(s => ({
|