@reventlessdev/reventless-local 3.0.0-alpha.246 → 3.0.0-alpha.248

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 CHANGED
@@ -3,6 +3,21 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 3.0.0-alpha.248 (2026-09-08)
7
+
8
+ ### Features
9
+
10
+ * a slice folder is named for its kind, without the Slice ([a400555](https://github.com/ReventlessDev/reventless-core/commit/a400555121b023823983ebe846e99cda27063c1f))
11
+ * **core:** a reference names a row and shows its picture ([2b40d04](https://github.com/ReventlessDev/reventless-core/commit/2b40d0418bba2bf83463f446e94e372ea0c9898c))
12
+
13
+
14
+ # 3.0.0-alpha.247 (2026-09-07)
15
+
16
+ ### Bug Fixes
17
+
18
+ * **core:** a state view slice composes its [@display](https://github.com/display)Name like a read model ([851aa1d](https://github.com/ReventlessDev/reventless-core/commit/851aa1d12ddae9dd39f91084f5719cd98fe1cbd4))
19
+
20
+
6
21
  # 3.0.0-alpha.246 (2026-09-07)
7
22
 
8
23
  ### Bug Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-local",
3
- "version": "3.0.0-alpha.246",
3
+ "version": "3.0.0-alpha.248",
4
4
  "description": "Local platform for Reventless (in-memory or SQLite backend, for development and testing without AWS)",
5
5
  "license": "Apache-2.0",
6
6
  "bin": {
@@ -36,17 +36,17 @@
36
36
  "ws": "^8.18.0",
37
37
  "@reventlessdev/rescript-effect": "0.1.0-alpha.32",
38
38
  "@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.27",
39
- "@reventlessdev/rescript-jest": "1.0.0-alpha.10",
40
- "@reventlessdev/rescript-node": "2.0.0-alpha.9",
41
39
  "@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.21",
40
+ "@reventlessdev/rescript-node": "2.0.0-alpha.9",
41
+ "@reventlessdev/rescript-jest": "1.0.0-alpha.10",
42
42
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19",
43
- "@reventlessdev/reventless-core": "3.0.0-alpha.257",
44
- "@reventlessdev/reventless-graphql-server": "1.0.0-alpha.105",
45
- "@reventlessdev/reventless-infra": "3.0.0-alpha.158",
46
- "@reventlessdev/reventless-postgres": "3.0.0-alpha.121",
47
- "@reventlessdev/reventless-gwt": "1.0.0-alpha.204",
43
+ "@reventlessdev/reventless-core": "3.0.0-alpha.259",
44
+ "@reventlessdev/reventless-gwt": "1.0.0-alpha.206",
45
+ "@reventlessdev/reventless-graphql-server": "1.0.0-alpha.107",
48
46
  "@reventlessdev/reventless-seed": "1.0.0-alpha.19",
49
- "@reventlessdev/reventless-spec": "3.0.0-alpha.130"
47
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.132",
48
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.160",
49
+ "@reventlessdev/reventless-postgres": "3.0.0-alpha.123"
50
50
  },
51
51
  "devDependencies": {
52
52
  "rescript": "12.3.0",
@@ -28,7 +28,7 @@ import * as Api_Naming$ReventlessCore from "@reventlessdev/reventless-core/src/c
28
28
  import * as PluginSpec$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/lifecycle/PluginSpec.res.mjs";
29
29
  import * as UserStore$ReventlessLocal from "./adapter/Auth/UserStore.res.mjs";
30
30
  import * as TestRunner$ReventlessLocal from "./test/TestRunner.res.mjs";
31
- import * as UiFragments$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments.res.mjs";
31
+ import * as UiFragments$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateView/UiFragments.res.mjs";
32
32
  import * as CommandTopic$ReventlessCore from "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic.res.mjs";
33
33
  import * as EffectLogger$ReventlessCore from "@reventlessdev/reventless-core/src/util/EffectLogger.res.mjs";
34
34
  import * as ShellConfig$ReventlessLocal from "./ShellConfig.res.mjs";
@@ -60,7 +60,7 @@ import * as LocalClonerRunner$ReventlessLocal from "./adapter/Cloner/LocalCloner
60
60
  import * as PluginBaseFragment$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/api/PluginBaseFragment.res.mjs";
61
61
  import * as ProjectionPending$ReventlessLocal from "./adapter/ProjectionPending.res.mjs";
62
62
  import * as ReadModel_Builder$ReventlessLocal from "./components/ReadModel_Builder.res.mjs";
63
- import * as UiFragmentRegistry$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs";
63
+ import * as UiFragmentRegistry$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateChange/UiFragmentRegistry.res.mjs";
64
64
  import * as LocalEvents_Server$ReventlessLocal from "./adapter/Api/LocalEvents_Server.res.mjs";
65
65
  import * as LocalPlatformStart$ReventlessLocal from "./LocalPlatformStart.res.mjs";
66
66
  import * as PlatformMCP_Server$ReventlessLocal from "./adapter/PlatformMCP_Server.res.mjs";
@@ -76,7 +76,7 @@ import * as ProjectionCheckpoint$ReventlessLocal from "./adapter/ProjectionCheck
76
76
  import * as ExtensionPointMapping$ReventlessInfra from "@reventlessdev/reventless-infra/src/types/ExtensionPointMapping.res.mjs";
77
77
  import * as LocalGeocodeResolvers$ReventlessLocal from "./adapter/LocalGeocodeResolvers.res.mjs";
78
78
  import * as LocalPlatformRegistry$ReventlessLocal from "./LocalPlatformRegistry.res.mjs";
79
- import * as UiFragments_Projection$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments_Projection.res.mjs";
79
+ import * as UiFragments_Projection$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateView/UiFragments_Projection.res.mjs";
80
80
  import * as EventLogStorage_Sqlite$ReventlessLocal from "./adapter/EventLog/EventLogStorage_Sqlite.res.mjs";
81
81
  import * as ExtensionPoint_Builder$ReventlessLocal from "./components/ExtensionPoint_Builder.res.mjs";
82
82
  import * as PlatformGraphQL_Server$ReventlessLocal from "./adapter/PlatformGraphQL_Server.res.mjs";
@@ -94,7 +94,7 @@ import * as StateChangeSlice_Builder$ReventlessLocal from "./components/StateCha
94
94
  import * as DcbEventLogStorage_Sqlite$ReventlessLocal from "./adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res.mjs";
95
95
  import * as LocalEventCollectorChannel$ReventlessLocal from "./adapter/EventCollector/LocalEventCollectorChannel.res.mjs";
96
96
  import * as PluginRuntime_Builder_Micro$ReventlessCore from "@reventlessdev/reventless-core/src/adapter/Runtime/PluginRuntime_Builder_Micro.res.mjs";
97
- import * as UiFragmentRegistry_Behavior$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry_Behavior.res.mjs";
97
+ import * as UiFragmentRegistry_Behavior$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateChange/UiFragmentRegistry_Behavior.res.mjs";
98
98
  import * as Platform_PluginStructuresApi$ReventlessCore from "@reventlessdev/reventless-core/src/admin/Platform_PluginStructuresApi.res.mjs";
99
99
  import * as EventHistoryResolvers_GraphQL$ReventlessLocal from "./adapter/EventHistory/EventHistoryResolvers_GraphQL.res.mjs";
100
100
  import * as InboundTranslationSlice_Builder$ReventlessLocal from "./components/InboundTranslationSlice_Builder.res.mjs";
@@ -190,6 +190,14 @@ module Make = (Bus: LocalBus.T) => {
190
190
  ->Option.flatMap(Reventless.StateAnnotations.getSpec)
191
191
  ->Option.flatMap(spec => spec.retired)
192
192
 
193
+ // The picture a reference to one of these rows shows it by, derived once for
194
+ // every backend in `Reventless.RowImage`. Read per request for the same
195
+ // reason the two above are.
196
+ let imageSourceOf = () =>
197
+ Plugin_Helpers.stateSchemaRegistry
198
+ ->Dict.get(name)
199
+ ->Option.flatMap(Reventless.RowImage.sourceFrom)
200
+
193
201
  // `includeRetired` is the caller asking; `decideRetired` decides whether the
194
202
  // asking counts. Read here rather than inside the decision so the argument
195
203
  // stays an argument — the door reports what was asked, the classifier says
@@ -500,10 +508,19 @@ module Make = (Bus: LocalBus.T) => {
500
508
  // A view with no label field resolves to its id, which is
501
509
  // what `labelField`'s own fallback already decided.
502
510
  ->Option.getOr(id)
511
+ // The picture travels with the name, so a retired row that
512
+ // keeps one keeps the other: an archived product reads as
513
+ // itself on the order that bought it.
514
+ let image =
515
+ switch (imageSourceOf(), item->JSON.Decode.object) {
516
+ | (Some(source), Some(d)) => d->Reventless.RowImage.refFrom(source)
517
+ | _ => None
518
+ }
503
519
  Some(
504
520
  Dict.fromArray([
505
521
  ("id", JSON.Encode.string(id)),
506
522
  ("label", JSON.Encode.string(label)),
523
+ ("image", image->Option.mapOr(JSON.Encode.null, JSON.Encode.string)),
507
524
  ("retired", JSON.Encode.bool(retired)),
508
525
  (
509
526
  "retiredState",
@@ -10,6 +10,7 @@ import * as Stdlib_Nullable from "@rescript/runtime/lib/es6/Stdlib_Nullable.js";
10
10
  import * as Owner$Reventless from "@reventlessdev/reventless-spec/src/components/Owner.res.mjs";
11
11
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
12
12
  import * as Identity$Reventless from "@reventlessdev/reventless-spec/src/types/Identity.res.mjs";
13
+ import * as RowImage$Reventless from "@reventlessdev/reventless-spec/src/semantic/RowImage.res.mjs";
13
14
  import * as ReadModel$Reventless from "@reventlessdev/reventless-spec/src/components/ReadModel.res.mjs";
14
15
  import * as OwnerScope$Reventless from "@reventlessdev/reventless-spec/src/types/OwnerScope.res.mjs";
15
16
  import * as Api_Ids$ReventlessCore from "@reventlessdev/reventless-core/src/components/Api/Api_Ids.res.mjs";
@@ -106,6 +107,7 @@ function Make(Bus) {
106
107
  return Stdlib_Option.mapOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(item), d => d[field]), Stdlib_JSON.Decode.string), false, v => v === required);
107
108
  };
108
109
  let retiredSpecOf = () => Stdlib_Option.flatMap(Stdlib_Option.flatMap(Plugin_Helpers$ReventlessCore.stateSchemaRegistry[name], StateAnnotations$Reventless.getSpec), spec => spec.retired);
110
+ let imageSourceOf = () => Stdlib_Option.flatMap(Plugin_Helpers$ReventlessCore.stateSchemaRegistry[name], RowImage$Reventless.sourceFrom);
109
111
  let askedForRetired = args => Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(args), d => d["includeRetired"]), Stdlib_JSON.Decode.bool), false);
110
112
  let retiredDecision = (ctx, args) => OwnerScope$Reventless.decideRetired(extractIdentity(ctx), Stdlib_Option.map(retiredSpecOf(), r => r.field), Stdlib_Option.flatMap(retiredSpecOf(), r => r.values), askedForRetired(args), undefined);
111
113
  let retiredAllows = (ctx, args, item) => {
@@ -289,6 +291,9 @@ function Make(Bus) {
289
291
  return;
290
292
  }
291
293
  let label = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(item), d => d[labelField]), Stdlib_JSON.Decode.string), id);
294
+ let match$1 = imageSourceOf();
295
+ let match$2 = Stdlib_JSON.Decode.object(item);
296
+ let image = match$1 !== undefined && match$2 !== undefined ? RowImage$Reventless.refFrom(match$2, match$1) : undefined;
292
297
  return Object.fromEntries([
293
298
  [
294
299
  "id",
@@ -298,6 +303,10 @@ function Make(Bus) {
298
303
  "label",
299
304
  label
300
305
  ],
306
+ [
307
+ "image",
308
+ Stdlib_Option.mapOr(image, null, prim => prim)
309
+ ],
301
310
  [
302
311
  "retired",
303
312
  retired
@@ -8,7 +8,7 @@ import * as Offload$Reventless from "@reventlessdev/reventless-spec/src/semantic
8
8
  import * as Backend$ReventlessLocal from "../adapter/Backend.res.mjs";
9
9
  import * as PluginSpec$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/lifecycle/PluginSpec.res.mjs";
10
10
  import * as Seed_Prompt$ReventlessSeed from "@reventlessdev/reventless-seed/src/Seed_Prompt.res.mjs";
11
- import * as UiFragments$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments.res.mjs";
11
+ import * as UiFragments$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateView/UiFragments.res.mjs";
12
12
  import * as ComponentType$ReventlessCore from "@reventlessdev/reventless-core/src/ComponentType.res.mjs";
13
13
  import * as SqliteDriver$ReventlessLocal from "../adapter/SqliteDriver.res.mjs";
14
14
  import * as LocalSeedTarget$ReventlessLocal from "../LocalSeedTarget.res.mjs";
@@ -7,7 +7,7 @@ import * as PluginSpec$ReventlessCore from "@reventlessdev/reventless-core/src/p
7
7
  import * as TestRunner$ReventlessLocal from "../src/test/TestRunner.res.mjs";
8
8
  import * as ComponentType$ReventlessCore from "@reventlessdev/reventless-core/src/ComponentType.res.mjs";
9
9
  import * as Plugin_Fixtures$ReventlessLocal from "./plugin/Plugin_Fixtures.res.mjs";
10
- import * as UiFragmentRegistry$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs";
10
+ import * as UiFragmentRegistry$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateChange/UiFragmentRegistry.res.mjs";
11
11
  import * as Platform_Admin_Structure$ReventlessCore from "@reventlessdev/reventless-core/src/admin/Platform_Admin_Structure.res.mjs";
12
12
 
13
13
  TestRunner$ReventlessLocal.setup();
@@ -0,0 +1,98 @@
1
+ // E2E fixtures for the @displayName overlay on a StateViewSlice.
2
+ // A slice's state carries the same synthetic `displayName` a read model's does;
3
+ // this builds one by hand (the ppx writes the field and the metadata) so the
4
+ // projection path can be asserted to compose it.
5
+
6
+ open Reventless.Projection
7
+
8
+ module OrderEventLog = {
9
+ @schema
10
+ type event =
11
+ | OrderPlaced({id: @s.matches(Reventless.DcbTag.string) string, placedAt: string})
12
+ | OrderShipped({id: @s.matches(Reventless.DcbTag.string) string, shippedAt: string})
13
+ }
14
+
15
+ module OrdersViewSpec = {
16
+ let name = "DnOrdersView"
17
+ let moduleUrl: string = %raw(`import.meta.url`)
18
+
19
+ @schema
20
+ type consumedEvent =
21
+ | OrderPlaced({id: string, placedAt: string})
22
+ | OrderShipped({id: string, shippedAt: string})
23
+
24
+ @schema
25
+ type state = {
26
+ id: string,
27
+ placedAt: string,
28
+ shippedAt: string,
29
+ displayName: option<string>,
30
+ }
31
+
32
+ // What the ppx emits for `@displayName placedAt`.
33
+ let stateSchema =
34
+ stateSchema->S.Metadata.set(
35
+ ~id=Reventless.DisplayName.displayNameId,
36
+ {Reventless.DisplayName.fields: ["placedAt"], separator: " "},
37
+ )
38
+
39
+ let config = Reventless.ReadModel.config()
40
+ let subIdConfig = None
41
+ }
42
+
43
+ module OrdersViewProjection = {
44
+ module Spec = OrdersViewSpec
45
+ open OrdersViewSpec
46
+
47
+ let moduleUrl: string = %raw(`import.meta.url`)
48
+
49
+ let project = ({event}: Reventless.StateViewSlice.consumed<consumedEvent>) =>
50
+ switch event {
51
+ | OrderPlaced({id, placedAt}) =>
52
+ [Set(id, {id, placedAt, shippedAt: "", displayName: None})]
53
+ | OrderShipped({id, shippedAt}) => [Update(id, s => {...s, shippedAt})]
54
+ }
55
+ }
56
+
57
+ module Bus = LocalBus.Make()
58
+
59
+ let _ = TestRunner.setup()
60
+
61
+ module OrderEventLogMaker = DcbEventLog_Builder.Make(Bus)
62
+ let eventLog = OrderEventLogMaker.make(
63
+ ~name="DnOrderEventLog",
64
+ ~partitionTag=Reventless.DcbTag.Simple({key: "id"}),
65
+ )
66
+
67
+ module SVMaker = StateViewSlice_Builder.Make(Bus)
68
+ module OrdersViewMaker = SVMaker.Make(OrdersViewSpec, OrdersViewProjection)
69
+ let sv = OrdersViewMaker.make(~dcbEventLog=eventLog)
70
+
71
+ let dcbEventTopicResource =
72
+ (eventLog->ReventlessCore.Component.outputs).eventTopic.resources->Array.getUnsafe(0)
73
+
74
+ let encodeEvent = (event: OrderEventLog.event): ReventlessInfra.DcbEventLog.rawEvent => {
75
+ let json = event->Reventless.Util_Sury.toJson(OrderEventLog.eventSchema)
76
+ let (eventType, data) = json->ReventlessCore.Message.splitMessage
77
+ let tags = Reventless.DcbTag.extractTags(OrderEventLog.eventSchema, event)
78
+ let meta = ReventlessCore.Message.generateMeta(~service="test")
79
+ {eventType, data: JSON.Object(data), tags, meta}
80
+ }
81
+
82
+ let appendEvent = async event => {
83
+ let ops = await eventLog->OrderEventLogMaker.operations->TestRunner.resolve
84
+ let _ = await ops.append([encodeEvent(event)])
85
+ }
86
+
87
+ let loadState = async id => {
88
+ switch Bus.getQueryDb("DnOrdersView") {
89
+ | None => []
90
+ | Some(ops) =>
91
+ let states =
92
+ await ops.loadStream(id)
93
+ ->Stream.runCollect
94
+ ->Effect.catchAll(_ => Effect.succeed([]))
95
+ ->Effect.runPromise
96
+ states->Array.map(json => json->Reventless.Util_Sury.fromJson(OrdersViewSpec.stateSchema))
97
+ }
98
+ }
@@ -0,0 +1,187 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Sury from "sury";
4
+ import * as Stream from "@reventlessdev/rescript-effect/src/Stream.res.mjs";
5
+ import * as Effect from "effect/Effect";
6
+ import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
7
+ import * as ReadModel$Reventless from "@reventlessdev/reventless-spec/src/components/ReadModel.res.mjs";
8
+ import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
9
+ import * as DisplayName$Reventless from "@reventlessdev/reventless-spec/src/components/DisplayName.res.mjs";
10
+ import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
11
+ import * as Component$ReventlessCore from "@reventlessdev/reventless-core/src/components/Component.res.mjs";
12
+ import * as LocalBus$ReventlessLocal from "../../../src/adapter/LocalBus.res.mjs";
13
+ import * as TestRunner$ReventlessLocal from "../../../src/test/TestRunner.res.mjs";
14
+ import * as DcbEventLog_Builder$ReventlessLocal from "../../../src/components/DcbEventLog_Builder.res.mjs";
15
+ import * as StateViewSlice_Builder$ReventlessLocal from "../../../src/components/StateViewSlice_Builder.res.mjs";
16
+
17
+ let eventSchema = Sury.union([
18
+ Sury.$schema(s => ({
19
+ TAG: "OrderPlaced",
20
+ id: s.m(DcbTag$Reventless.string),
21
+ placedAt: s.m(Sury.string)
22
+ })),
23
+ Sury.$schema(s => ({
24
+ TAG: "OrderShipped",
25
+ id: s.m(DcbTag$Reventless.string),
26
+ shippedAt: s.m(Sury.string)
27
+ }))
28
+ ]);
29
+
30
+ let OrderEventLog = {
31
+ eventSchema: eventSchema
32
+ };
33
+
34
+ let name = "DnOrdersView";
35
+
36
+ let moduleUrl = import.meta.url;
37
+
38
+ let consumedEventSchema = Sury.union([
39
+ Sury.$schema(s => ({
40
+ TAG: "OrderPlaced",
41
+ id: s.m(Sury.string),
42
+ placedAt: s.m(Sury.string)
43
+ })),
44
+ Sury.$schema(s => ({
45
+ TAG: "OrderShipped",
46
+ id: s.m(Sury.string),
47
+ shippedAt: s.m(Sury.string)
48
+ }))
49
+ ]);
50
+
51
+ let stateSchema = Sury.$schema(s => ({
52
+ id: s.m(Sury.string),
53
+ placedAt: s.m(Sury.string),
54
+ shippedAt: s.m(Sury.string),
55
+ displayName: s.m(Sury.$option(Sury.string))
56
+ }));
57
+
58
+ let stateSchema$1 = Sury.$Metadata_set(stateSchema, DisplayName$Reventless.displayNameId, {
59
+ fields: ["placedAt"],
60
+ separator: " "
61
+ });
62
+
63
+ let config = ReadModel$Reventless.config(undefined, undefined, undefined);
64
+
65
+ let OrdersViewSpec = {
66
+ name: name,
67
+ moduleUrl: moduleUrl,
68
+ consumedEventSchema: consumedEventSchema,
69
+ stateSchema: stateSchema$1,
70
+ config: config,
71
+ subIdConfig: undefined,
72
+ authorization: "AllowAuthenticated",
73
+ visibility: "Public"
74
+ };
75
+
76
+ let moduleUrl$1 = import.meta.url;
77
+
78
+ function project(param) {
79
+ let event = param.event;
80
+ if (event.TAG === "OrderPlaced") {
81
+ let id = event.id;
82
+ return [{
83
+ TAG: "Set",
84
+ _0: id,
85
+ _1: {
86
+ id: id,
87
+ placedAt: event.placedAt,
88
+ shippedAt: "",
89
+ displayName: undefined
90
+ }
91
+ }];
92
+ }
93
+ let shippedAt = event.shippedAt;
94
+ return [{
95
+ TAG: "Update",
96
+ _0: event.id,
97
+ _1: s => ({
98
+ id: s.id,
99
+ placedAt: s.placedAt,
100
+ shippedAt: shippedAt,
101
+ displayName: s.displayName
102
+ })
103
+ }];
104
+ }
105
+
106
+ let OrdersViewProjection = {
107
+ Spec: undefined,
108
+ moduleUrl: moduleUrl$1,
109
+ project: project
110
+ };
111
+
112
+ let Bus = LocalBus$ReventlessLocal.Make({});
113
+
114
+ TestRunner$ReventlessLocal.setup();
115
+
116
+ let OrderEventLogMaker = DcbEventLog_Builder$ReventlessLocal.Make(Bus);
117
+
118
+ let eventLog = OrderEventLogMaker.make("DnOrderEventLog", undefined, {
119
+ TAG: "Simple",
120
+ _0: {
121
+ key: "id"
122
+ }
123
+ }, undefined);
124
+
125
+ let SVMaker = StateViewSlice_Builder$ReventlessLocal.Make(Bus);
126
+
127
+ let OrdersViewMaker = SVMaker.Make({
128
+ name: name,
129
+ moduleUrl: moduleUrl,
130
+ stateSchema: stateSchema$1,
131
+ consumedEventSchema: consumedEventSchema,
132
+ config: config,
133
+ subIdConfig: undefined,
134
+ authorization: "AllowAuthenticated",
135
+ visibility: "Public"
136
+ })({
137
+ project: project,
138
+ moduleUrl: moduleUrl$1
139
+ });
140
+
141
+ let sv = OrdersViewMaker.make(eventLog, undefined, undefined);
142
+
143
+ let dcbEventTopicResource = Component$ReventlessCore.outputs(eventLog).eventTopic.resources[0];
144
+
145
+ function encodeEvent(event) {
146
+ let json = Util_Sury$Reventless.toJson(event, eventSchema);
147
+ let match = Message$ReventlessCore.splitMessage(json);
148
+ let tags = DcbTag$Reventless.extractTags(eventSchema, event);
149
+ let meta = Message$ReventlessCore.generateMeta("test", undefined, undefined, undefined, undefined, undefined, undefined, undefined);
150
+ return {
151
+ eventType: match[0],
152
+ data: match[1],
153
+ tags: tags,
154
+ meta: meta
155
+ };
156
+ }
157
+
158
+ async function appendEvent(event) {
159
+ let ops = await TestRunner$ReventlessLocal.resolve(OrderEventLogMaker.operations(eventLog));
160
+ await ops.append([encodeEvent(event)], undefined);
161
+ }
162
+
163
+ async function loadState(id) {
164
+ let ops = Bus.getQueryDb("DnOrdersView");
165
+ if (ops === undefined) {
166
+ return [];
167
+ }
168
+ let states = await Effect.runPromise(Effect.catchAll(Stream.runCollect(ops.loadStream(id)), param => Effect.succeed([])));
169
+ return states.map(json => Util_Sury$Reventless.fromJson(json, stateSchema$1));
170
+ }
171
+
172
+ export {
173
+ OrderEventLog,
174
+ OrdersViewSpec,
175
+ OrdersViewProjection,
176
+ Bus,
177
+ OrderEventLogMaker,
178
+ eventLog,
179
+ SVMaker,
180
+ OrdersViewMaker,
181
+ sv,
182
+ dcbEventTopicResource,
183
+ encodeEvent,
184
+ appendEvent,
185
+ loadState,
186
+ }
187
+ /* eventSchema Not a pure module */
@@ -0,0 +1,32 @@
1
+ // The @displayName overlay on the StateViewSlice projection path.
2
+ // Without it the column stays null and every surface names the row by its id.
3
+
4
+ open JestGlobals
5
+ open StateViewSliceDisplayNameFixtures
6
+
7
+ describe("StateViewSlice @displayName", () => {
8
+ let _ = beforeAllAsync(async () => {
9
+ let _ = await sv->OrdersViewMaker.operations->TestRunner.resolve
10
+ let _ = await dcbEventTopicResource.name->TestRunner.resolve
11
+ })
12
+
13
+ testPromise("a projected state carries the composed label", async () => {
14
+ let _ = await appendEvent(
15
+ OrderEventLog.OrderPlaced({id: "order-1", placedAt: "2026-09-01T10:00:00.000Z"}),
16
+ )
17
+ let states = await loadState("order-1")
18
+ expect(states->Array.length)->toBe(1)
19
+ let s = states->Array.getUnsafe(0)
20
+ expect(s.displayName)->toEqual(Some("2026-09-01T10:00:00.000Z"))
21
+ })
22
+
23
+ testPromise("an update recomposes it from the state it wrote", async () => {
24
+ let _ = await appendEvent(
25
+ OrderEventLog.OrderShipped({id: "order-1", shippedAt: "2026-09-02T10:00:00.000Z"}),
26
+ )
27
+ let states = await loadState("order-1")
28
+ let s = states->Array.getUnsafe(0)
29
+ expect(s.shippedAt)->toBe("2026-09-02T10:00:00.000Z")
30
+ expect(s.displayName)->toEqual(Some("2026-09-01T10:00:00.000Z"))
31
+ })
32
+ })
@@ -0,0 +1,35 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as TestRunner$ReventlessLocal from "../../../src/test/TestRunner.res.mjs";
4
+ import * as StateViewSliceDisplayNameFixtures$ReventlessLocal from "./StateViewSliceDisplayNameFixtures.res.mjs";
5
+
6
+ globalThis.describe("StateViewSlice @displayName", () => {
7
+ globalThis.beforeAll(async () => {
8
+ await TestRunner$ReventlessLocal.resolve(StateViewSliceDisplayNameFixtures$ReventlessLocal.OrdersViewMaker.operations(StateViewSliceDisplayNameFixtures$ReventlessLocal.sv));
9
+ await TestRunner$ReventlessLocal.resolve(StateViewSliceDisplayNameFixtures$ReventlessLocal.dcbEventTopicResource.name);
10
+ });
11
+ globalThis.test("a projected state carries the composed label", async () => {
12
+ await StateViewSliceDisplayNameFixtures$ReventlessLocal.appendEvent({
13
+ TAG: "OrderPlaced",
14
+ id: "order-1",
15
+ placedAt: "2026-09-01T10:00:00.000Z"
16
+ });
17
+ let states = await StateViewSliceDisplayNameFixtures$ReventlessLocal.loadState("order-1");
18
+ globalThis.expect(states.length).toBe(1);
19
+ let s = states[0];
20
+ globalThis.expect(s.displayName).toEqual("2026-09-01T10:00:00.000Z");
21
+ });
22
+ globalThis.test("an update recomposes it from the state it wrote", async () => {
23
+ await StateViewSliceDisplayNameFixtures$ReventlessLocal.appendEvent({
24
+ TAG: "OrderShipped",
25
+ id: "order-1",
26
+ shippedAt: "2026-09-02T10:00:00.000Z"
27
+ });
28
+ let states = await StateViewSliceDisplayNameFixtures$ReventlessLocal.loadState("order-1");
29
+ let s = states[0];
30
+ globalThis.expect(s.shippedAt).toBe("2026-09-02T10:00:00.000Z");
31
+ globalThis.expect(s.displayName).toEqual("2026-09-01T10:00:00.000Z");
32
+ });
33
+ });
34
+
35
+ /* Not a pure module */
@@ -2,8 +2,8 @@
2
2
 
3
3
  import * as Behavior_GWT$ReventlessGwt from "@reventlessdev/reventless-gwt/src/Behavior_GWT.res.mjs";
4
4
  import * as Plugin_Fixtures$ReventlessLocal from "./Plugin_Fixtures.res.mjs";
5
- import * as UiFragmentRegistry$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs";
6
- import * as UiFragmentRegistry_Behavior$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry_Behavior.res.mjs";
5
+ import * as UiFragmentRegistry$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateChange/UiFragmentRegistry.res.mjs";
6
+ import * as UiFragmentRegistry_Behavior$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateChange/UiFragmentRegistry_Behavior.res.mjs";
7
7
 
8
8
  let Test = Behavior_GWT$ReventlessGwt.Make({
9
9
  name: UiFragmentRegistry$ReventlessCore.name,
@@ -1,9 +1,9 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as UiFragments$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments.res.mjs";
3
+ import * as UiFragments$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateView/UiFragments.res.mjs";
4
4
  import * as Projection_GWT$ReventlessGwt from "@reventlessdev/reventless-gwt/src/Projection_GWT.res.mjs";
5
5
  import * as Plugin_Fixtures$ReventlessLocal from "./Plugin_Fixtures.res.mjs";
6
- import * as UiFragments_Projection$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments_Projection.res.mjs";
6
+ import * as UiFragments_Projection$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateView/UiFragments_Projection.res.mjs";
7
7
 
8
8
  let Test = Projection_GWT$ReventlessGwt.Make({
9
9
  name: UiFragments$ReventlessCore.name,