@reventlessdev/reventless-core 3.0.0-alpha.191 → 3.0.0-alpha.193

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 (32) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/package.json +6 -6
  3. package/src/admin/Platform_Admin.res.mjs +4 -0
  4. package/src/admin/Platform_Admin_Structure.res +1 -0
  5. package/src/admin/Platform_Admin_Structure.res.mjs +2 -1
  6. package/src/components/Aggregate/Aggregate.res +7 -7
  7. package/src/components/Aggregate/Aggregate.res.mjs +7 -2
  8. package/src/components/Aggregate/Aggregate_Builder.res +4 -1
  9. package/src/components/Aggregate/Aggregate_Builder.res.mjs +11 -3
  10. package/src/components/Builder_Helpers.res +37 -4
  11. package/src/components/Builder_Helpers.res.mjs +24 -2
  12. package/src/components/SideEffectHandler/SideEffectHandler.res +11 -0
  13. package/src/components/SideEffectHandler/SideEffectHandler_Builder.res +2 -0
  14. package/src/components/SideEffectHandler/SideEffectHandler_Builder.res.mjs +3 -1
  15. package/src/components/Task/Task_Builder.res +11 -0
  16. package/src/components/Task/Task_Builder.res.mjs +2 -0
  17. package/src/plugin/component/Capability_Inference.res +68 -0
  18. package/src/plugin/component/Capability_Inference.res.mjs +79 -0
  19. package/src/plugin/component/Plugin_Helpers.res +18 -7
  20. package/src/plugin/component/Plugin_Helpers.res.mjs +20 -1
  21. package/src/plugin/component/Plugin_Structure.res +91 -34
  22. package/src/plugin/component/Plugin_Structure.res.mjs +82 -12
  23. package/tests/admin/Platform_ComponentDefinitionsApiTest.res +2 -0
  24. package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +8 -4
  25. package/tests/api/SuryToJsonSchemaTest.res +42 -0
  26. package/tests/api/SuryToJsonSchemaTest.res.mjs +36 -0
  27. package/tests/message/MessageTest.res +1 -0
  28. package/tests/message/MessageTest.res.mjs +2 -1
  29. package/tests/plugin/PluginStructureTest.res +145 -0
  30. package/tests/plugin/PluginStructureTest.res.mjs +138 -0
  31. package/tests/plugin/StateChangeSlice/PsChangePhoto.res +33 -0
  32. package/tests/plugin/StateChangeSlice/PsChangePhoto.res.mjs +64 -0
@@ -11,10 +11,13 @@ import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/seman
11
11
  import * as PsShipOrder$ReventlessCore from "./StateChangeSlice/PsShipOrder.res.mjs";
12
12
  import * as PsOrdersView$ReventlessCore from "./StateViewSlice/PsOrdersView.res.mjs";
13
13
  import * as PsPlaceOrder$ReventlessCore from "./StateChangeSlice/PsPlaceOrder.res.mjs";
14
+ import * as PsChangePhoto$ReventlessCore from "./StateChangeSlice/PsChangePhoto.res.mjs";
15
+ import * as CapabilityManifest$Reventless from "@reventlessdev/reventless-spec/src/components/CapabilityManifest.res.mjs";
14
16
  import * as PsAnnotatedView$ReventlessCore from "./StateViewSlice/PsAnnotatedView.res.mjs";
15
17
  import * as PsAttachInvoice$ReventlessCore from "./StateChangeSlice/PsAttachInvoice.res.mjs";
16
18
  import * as PsCustomersView$ReventlessCore from "./StateViewSlice/PsCustomersView.res.mjs";
17
19
  import * as Plugin_Structure$ReventlessCore from "../../src/plugin/component/Plugin_Structure.res.mjs";
20
+ import * as Capability_Inference$ReventlessCore from "../../src/plugin/component/Capability_Inference.res.mjs";
18
21
  import * as PsAvailableProductsView$ReventlessCore from "./StateViewSlice/PsAvailableProductsView.res.mjs";
19
22
 
20
23
  let Behavior = {
@@ -211,6 +214,36 @@ let PsAttachInvoiceSlice = {
211
214
  make: make$6
212
215
  };
213
216
 
217
+ let Behavior$3 = {
218
+ initialState: false,
219
+ evolve: PsChangePhoto$ReventlessCore.evolve,
220
+ decide: PsChangePhoto$ReventlessCore.decide,
221
+ moduleUrl: PsChangePhoto$ReventlessCore.moduleUrl
222
+ };
223
+
224
+ function make$7(param, param$1, param$2, param$3, param$4, param$5) {
225
+ return 0;
226
+ }
227
+
228
+ let PsChangePhotoSlice_Spec = {
229
+ name: PsChangePhoto$ReventlessCore.name,
230
+ moduleUrl: PsChangePhoto$ReventlessCore.moduleUrl,
231
+ Id: Id$Reventless.$$String,
232
+ consumedEventSchema: PsChangePhoto$ReventlessCore.consumedEventSchema,
233
+ errorSchema: PsChangePhoto$ReventlessCore.errorSchema,
234
+ eventSchema: PsChangePhoto$ReventlessCore.eventSchema,
235
+ commandSchema: PsChangePhoto$ReventlessCore.commandSchema,
236
+ commandAuthorization: PsChangePhoto$ReventlessCore.commandAuthorization,
237
+ readConsistency: PsChangePhoto$ReventlessCore.readConsistency
238
+ };
239
+
240
+ let PsChangePhotoSlice = {
241
+ Spec: PsChangePhotoSlice_Spec,
242
+ Behavior: Behavior$3,
243
+ isAsync: false,
244
+ make: make$7
245
+ };
246
+
214
247
  let structure = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, [
215
248
  PsOrdersViewSlice,
216
249
  PsAvailableProductsViewSlice,
@@ -719,6 +752,110 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
719
752
  globalThis.test("a plugin declaring no stores collects none — not None", () => {
720
753
  globalThis.expect(structure.requiredStores).toEqual([]);
721
754
  });
755
+ globalThis.test("each requirement keeps its declaring (component, field) sites", () => {
756
+ let expected = [
757
+ {
758
+ store: "TestPlugin.documents",
759
+ component: "AttachInvoice",
760
+ field: "documentUrl"
761
+ },
762
+ {
763
+ store: "branding.logos",
764
+ component: "AttachInvoice",
765
+ field: "logoUrl"
766
+ }
767
+ ];
768
+ globalThis.expect(withStores.requiredStoreDeclarations).toEqual(expected);
769
+ });
770
+ globalThis.describe("capability manifest", () => {
771
+ let manifest = CapabilityManifest$Reventless.fromStructure(withStores);
772
+ globalThis.test("keys are byte-identical to requiredStores", () => {
773
+ globalThis.expect(manifest.capabilities.map(c => c.key)).toEqual(Stdlib_Option.getOr(withStores.requiredStores, []));
774
+ });
775
+ globalThis.test("each entry carries its provenance", () => {
776
+ let entry = Stdlib_Option.getOrThrow(manifest.capabilities.find(c => c.key === "TestPlugin.documents"), undefined);
777
+ let expected = [{
778
+ component: "AttachInvoice",
779
+ field: "documentUrl"
780
+ }];
781
+ globalThis.expect(entry.declaredBy).toEqual(expected);
782
+ });
783
+ globalThis.test("a structure declaring nothing yields an empty list, not a missing manifest", () => {
784
+ globalThis.expect(CapabilityManifest$Reventless.fromStructure(structure).capabilities).toEqual([]);
785
+ });
786
+ globalThis.test("rendering is deterministic and newline-terminated", () => {
787
+ let rendered = CapabilityManifest$Reventless.renderForStructure(withStores);
788
+ globalThis.expect(rendered).toBe(`{
789
+ "capabilities": [
790
+ {
791
+ "kind": "ObjectStore",
792
+ "key": "TestPlugin.documents",
793
+ "declaredBy": [
794
+ {
795
+ "component": "AttachInvoice",
796
+ "field": "documentUrl"
797
+ }
798
+ ]
799
+ },
800
+ {
801
+ "kind": "ObjectStore",
802
+ "key": "branding.logos",
803
+ "declaredBy": [
804
+ {
805
+ "component": "AttachInvoice",
806
+ "field": "logoUrl"
807
+ }
808
+ ]
809
+ }
810
+ ]
811
+ }
812
+ `);
813
+ });
814
+ });
815
+ });
816
+ globalThis.describe("capability inference", () => {
817
+ let commandWarnings = Capability_Inference$ReventlessCore.scanSchema("ChangePhoto", PsChangePhoto$ReventlessCore.commandSchema);
818
+ let eventWarnings = Capability_Inference$ReventlessCore.scanSchema("ChangePhoto", PsChangePhoto$ReventlessCore.eventSchema);
819
+ globalThis.test("a heuristic-only match produces a warning", () => {
820
+ let expected = [{
821
+ component: "ChangePhoto",
822
+ field: "photoUrl"
823
+ }];
824
+ globalThis.expect(commandWarnings).toEqual(expected);
825
+ });
826
+ globalThis.test("a declared field with a heuristic name does not warn", () => {
827
+ let expected = [{
828
+ component: "ChangePhoto",
829
+ field: "photoUrl"
830
+ }];
831
+ globalThis.expect(eventWarnings).toEqual(expected);
832
+ });
833
+ globalThis.test("a heuristic-only match reaches no manifest entry", () => {
834
+ let withHeuristicField = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsChangePhotoSlice], undefined, undefined, undefined, undefined, undefined, undefined);
835
+ globalThis.expect(withHeuristicField.requiredStores).toEqual(["TestPlugin.productPhotos"]);
836
+ let manifest = CapabilityManifest$Reventless.fromStructure(withHeuristicField);
837
+ globalThis.expect(manifest.capabilities.every(entry => entry.declaredBy.every(site => site.field !== "photoUrl"))).toBe(true);
838
+ });
839
+ globalThis.test("the warning names the field and the settling annotation", () => {
840
+ let text = Capability_Inference$ReventlessCore.message(commandWarnings[0]);
841
+ globalThis.expect(text.includes("ChangePhoto.photoUrl")).toBe(true);
842
+ globalThis.expect(text.includes("@storageRef")).toBe(true);
843
+ });
844
+ globalThis.test("suffix and exact name rules match; ordinary names do not", () => {
845
+ globalThis.expect([
846
+ "invoiceFileRef",
847
+ "upload",
848
+ "thumbnail",
849
+ "customerName",
850
+ "documentUrl"
851
+ ].map(Capability_Inference$ReventlessCore.nameMatches)).toEqual([
852
+ true,
853
+ true,
854
+ true,
855
+ false,
856
+ false
857
+ ]);
858
+ });
722
859
  });
723
860
  });
724
861
 
@@ -730,6 +867,7 @@ export {
730
867
  PsCustomersViewSlice,
731
868
  PsAnnotatedViewSlice,
732
869
  PsAttachInvoiceSlice,
870
+ PsChangePhotoSlice,
733
871
  structure,
734
872
  }
735
873
  /* structure Not a pure module */
@@ -0,0 +1,33 @@
1
+ // Test fixture spec for heuristic capability inference.
2
+ //
3
+ // `photoUrl` matches the stored-object name heuristic but carries no
4
+ // `@storageRef` — the case that must produce a warning and no manifest entry.
5
+ // `caption` matches nothing, so the scan's silence on it is also exercised.
6
+
7
+ @@reventless.spec("ChangePhoto")
8
+
9
+ type state = bool
10
+ let initialState = false
11
+
12
+ @schema
13
+ type consumedEvent = OrderPlaced
14
+
15
+ let evolve = (_state, _event) => true
16
+
17
+ @schema
18
+ type command = ChangePhoto({productId: string, photoUrl: string, caption: string})
19
+
20
+ @schema
21
+ type error = ProductNotFound
22
+
23
+ // `thumbnail` matches the same name heuristic but IS declared — the case the
24
+ // lint must stay silent on, because the declaration already provisions it.
25
+ @schema
26
+ type event =
27
+ | PhotoChanged({
28
+ productId: string,
29
+ photoUrl: string,
30
+ @storageRef("productPhotos") thumbnail: string,
31
+ })
32
+
33
+ let decide = (_state, _command): result<array<event>, error> => Ok([])
@@ -0,0 +1,64 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as S from "sury/src/S.res.mjs";
4
+ import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
5
+ import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/StorageRef.res.mjs";
6
+
7
+ let consumedEventSchema = S.literal("OrderPlaced");
8
+
9
+ function evolve(_state, _event) {
10
+ return true;
11
+ }
12
+
13
+ let commandSchema = S.schema(s => ({
14
+ TAG: "ChangePhoto",
15
+ productId: s.m(DcbTag$Reventless.string),
16
+ photoUrl: s.m(S.string),
17
+ caption: s.m(S.string)
18
+ }));
19
+
20
+ let errorSchema = S.literal("ProductNotFound");
21
+
22
+ let eventSchema = S.schema(s => ({
23
+ TAG: "PhotoChanged",
24
+ productId: s.m(DcbTag$Reventless.string),
25
+ photoUrl: s.m(S.string),
26
+ thumbnail: s.m(StorageRef$Reventless.forStore(undefined, "productPhotos"))
27
+ }));
28
+
29
+ function decide(_state, _command) {
30
+ return {
31
+ TAG: "Ok",
32
+ _0: []
33
+ };
34
+ }
35
+
36
+ function commandAuthorization(param) {
37
+ return "AllowAuthenticated";
38
+ }
39
+
40
+ let name = "ChangePhoto";
41
+
42
+ let Id;
43
+
44
+ let initialState = false;
45
+
46
+ let moduleUrl = "@reventlessdev/reventless-core/tests/plugin/StateChangeSlice/PsChangePhoto.res.mjs";
47
+
48
+ let readConsistency = "EscalateOnRetry";
49
+
50
+ export {
51
+ name,
52
+ Id,
53
+ initialState,
54
+ consumedEventSchema,
55
+ evolve,
56
+ commandSchema,
57
+ errorSchema,
58
+ eventSchema,
59
+ decide,
60
+ moduleUrl,
61
+ commandAuthorization,
62
+ readConsistency,
63
+ }
64
+ /* consumedEventSchema Not a pure module */