@reventlessdev/reventless-core 3.0.0-alpha.239 → 3.0.0-alpha.241
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 +35 -0
- package/package.json +11 -11
- package/src/Message.res +11 -11
- package/src/Message.res.mjs +15 -14
- package/src/Projection.res +2 -2
- package/src/Projection.res.mjs +5 -4
- package/src/adapter/Monitoring/Monitoring.res +24 -2
- package/src/adapter/Monitoring/Monitoring.res.mjs +3 -3
- package/src/admin/Platform_Admin.res +1 -16
- package/src/admin/Platform_Admin.res.mjs +2 -30
- package/src/admin/Platform_AdminApi.res.mjs +3 -3
- package/src/admin/Platform_Admin_Structure.res +58 -113
- package/src/admin/Platform_Admin_Structure.res.mjs +24 -139
- package/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs +12 -12
- package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments.res.mjs +14 -14
- package/src/components/Aggregate/Aggregate_Callback.res +2 -2
- package/src/components/Aggregate/Aggregate_Callback.res.mjs +4 -4
- package/src/components/Api/ApiAllowedStatesHelpers.res.mjs +3 -3
- package/src/components/Api/ApiNoApiHelpers.res.mjs +5 -5
- package/src/components/Api/ApiTargetStateHelpers.res.mjs +3 -3
- package/src/components/Api/GraphQL_FragmentGenerator.res +18 -12
- package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +7 -13
- package/src/components/Api/GraphQL_SchemaInspector.res +1 -1
- package/src/components/Api/GraphQL_SchemaInspector.res.mjs +1 -1
- package/src/components/Api/MCP_SchemaGenerator.res +1 -1
- package/src/components/Api/MCP_SchemaGenerator.res.mjs +1 -1
- package/src/components/Api/SchemaType.res +6 -10
- package/src/components/Api/SchemaType.res.mjs +4 -4
- package/src/components/Api/StorageRefFields.res +1 -1
- package/src/components/Api/StorageRefFields.res.mjs +1 -1
- package/src/components/Api/SuryToJsonSchema.res +11 -0
- package/src/components/Api/SuryToJsonSchema.res.mjs +2 -1
- package/src/components/AutomationSlice/AutomationSlice_Callback.res +3 -4
- package/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs +22 -23
- package/src/components/CommandTopic/CommandTopic_Callback.res +1 -2
- package/src/components/CommandTopic/CommandTopic_Callback.res.mjs +3 -4
- package/src/components/CommandTopic/CommandTopic_Helpers.res +1 -1
- package/src/components/CommandTopic/CommandTopic_Helpers.res.mjs +3 -3
- package/src/components/Counter/Counter.res.mjs +2 -2
- package/src/components/Counter/Counter_Callback.res.mjs +4 -4
- package/src/components/Counter/Counter_Operations.res.mjs +4 -4
- package/src/components/Dcb/Dcb_Builder.res +1 -1
- package/src/components/Dcb/Dcb_Builder.res.mjs +8 -6
- package/src/components/DcbEventLog/DcbEventLog_Builder.res.mjs +4 -3
- package/src/components/EventCollector/EventCollector_Builder.res +1 -1
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res +1 -2
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs +11 -12
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res +3 -4
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs +24 -25
- package/src/components/SideEffectHandler/SideEffectHandler_Callback.res +1 -1
- package/src/components/SideEffectHandler/SideEffectHandler_Callback.res.mjs +3 -3
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +2 -2
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res.mjs +4 -4
- package/src/components/StateViewSlice/StateViewSlice_Builder.res +1 -1
- package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +3 -3
- package/src/plugin/api/PluginBaseFragment.res +12 -29
- package/src/plugin/api/PluginBaseFragment.res.mjs +3 -22
- package/src/plugin/component/Capability_Inference.res +118 -1
- package/src/plugin/component/Capability_Inference.res.mjs +128 -1
- package/src/plugin/component/Plugin_Builder.res +2 -2
- package/src/plugin/component/Plugin_Builder.res.mjs +2 -1
- package/src/plugin/component/Plugin_Helpers.res +11 -11
- package/src/plugin/component/Plugin_Helpers.res.mjs +11 -10
- package/src/plugin/component/Plugin_Structure.res +349 -274
- package/src/plugin/component/Plugin_Structure.res.mjs +212 -175
- package/src/plugin/component/Plugin_SubscriptionSchema.res +1 -1
- package/src/plugin/component/Plugin_SubscriptionSchema.res.mjs +1 -1
- package/src/plugin/component/SchemaWalker.res +11 -11
- package/src/plugin/component/SchemaWalker.res.mjs +8 -9
- package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +15 -15
- package/src/plugin/lifecycle/PluginBehavior.res.mjs +55 -55
- package/src/plugin/lifecycle/PluginSpec.res +22 -7
- package/src/plugin/lifecycle/PluginSpec.res.mjs +91 -36
- package/src/plugin/lifecycle/PluginsReadModelSpec.res +36 -9
- package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +33 -22
- package/src/util/Interstack.res +3 -3
- package/src/util/LogFormat.res +1 -2
- package/src/util/LogFormat.res.mjs +2 -2
- package/tests/IdentityTest.res +6 -7
- package/tests/IdentityTest.res.mjs +7 -9
- package/tests/adapter/MonitoringTest.res +30 -3
- package/tests/adapter/MonitoringTest.res.mjs +31 -12
- package/tests/adapter/RuntimeExtensionHookReachTest.res +0 -1
- package/tests/adapter/RuntimeExtensionHookReachTest.res.mjs +5 -7
- package/tests/admin/Platform_Admin_StructureTest.res +254 -0
- package/tests/admin/Platform_Admin_StructureTest.res.mjs +219 -0
- package/tests/aggregate/AggregateCacheTest.res +0 -1
- package/tests/aggregate/AggregateCacheTest.res.mjs +13 -15
- package/tests/aggregate/AggregateConflictTest.res +0 -1
- package/tests/aggregate/AggregateConflictTest.res.mjs +7 -9
- package/tests/aggregate/AggregateFixtures.res +0 -1
- package/tests/aggregate/AggregateFixtures.res.mjs +19 -21
- package/tests/aggregate/AggregateSnapshotTest.res +1 -2
- package/tests/aggregate/AggregateSnapshotTest.res.mjs +15 -16
- package/tests/api/ApiNoApiTest.res.mjs +17 -9
- package/tests/api/GraphQL_FragmentGeneratorTest.res +62 -1
- package/tests/api/GraphQL_FragmentGeneratorTest.res.mjs +102 -58
- package/tests/api/PsInternalFieldsReadModel.res +21 -0
- package/tests/api/PsInternalFieldsReadModel.res.mjs +74 -0
- package/tests/api/StorageRefFieldsTest.res.mjs +13 -13
- package/tests/api/SuryToJsonSchemaTest.res +43 -0
- package/tests/api/SuryToJsonSchemaTest.res.mjs +352 -849
- package/tests/commandgenerator/CommandGeneratorFixtures.res +0 -1
- package/tests/commandgenerator/CommandGeneratorFixtures.res.mjs +19 -21
- package/tests/commandgenerator/OwnerStampingTest.res +0 -1
- package/tests/commandgenerator/OwnerStampingTest.res.mjs +9 -11
- package/tests/commandtopic/CommandTopicCallbackFixtures.res +0 -1
- package/tests/commandtopic/CommandTopicCallbackFixtures.res.mjs +7 -9
- package/tests/counter/CounterFixtures.res +0 -1
- package/tests/counter/CounterFixtures.res.mjs +1 -4
- package/tests/dcb/DcbDecodeTest.res.mjs +24 -24
- package/tests/dcb/DcbEventLogOperationsTest.res +2 -2
- package/tests/dcb/DcbEventLogOperationsTest.res.mjs +3 -3
- package/tests/dcb/DcbEventLogSchemaTest.res.mjs +7 -7
- package/tests/dcb/DcbFixtures.res +0 -1
- package/tests/dcb/DcbFixtures.res.mjs +87 -89
- package/tests/dcb/DcbTagTest.res.mjs +6 -6
- package/tests/dcb/DcbValidationTest.res.mjs +52 -52
- package/tests/eventlog/EventLogFixtures.res +0 -1
- package/tests/eventlog/EventLogFixtures.res.mjs +7 -9
- package/tests/eventmapper/EventMapperFixtures.res +0 -1
- package/tests/eventmapper/EventMapperFixtures.res.mjs +24 -26
- package/tests/eventtopic/EventTopicFixtures.res +0 -1
- package/tests/eventtopic/EventTopicFixtures.res.mjs +7 -9
- package/tests/extensionpoint/ExtensionPointFixtures.res +0 -1
- package/tests/extensionpoint/ExtensionPointFixtures.res.mjs +10 -12
- package/tests/extensionpoint/ExtensionPointOperationsTest.res +1 -2
- package/tests/extensionpoint/ExtensionPointOperationsTest.res.mjs +9 -10
- package/tests/logger/LogFormatTest.res +3 -2
- package/tests/logger/LogFormatTest.res.mjs +7 -9
- package/tests/message/MessageTest.res +2 -2
- package/tests/message/MessageTest.res.mjs +8 -7
- package/tests/message/MetaEnvelopeTest.res +5 -5
- package/tests/message/MetaEnvelopeTest.res.mjs +12 -11
- package/tests/plugin/ManifestVisibilityTest.res.mjs +7 -7
- package/tests/plugin/PluginDefinitionScalars.res +5 -3
- package/tests/plugin/PluginDefinitionScalars.res.mjs +2 -2
- package/tests/plugin/PluginLifecycleCorpusTest.res +4 -3
- package/tests/plugin/PluginLifecycleCorpusTest.res.mjs +3 -6
- package/tests/plugin/PluginSpecExperiment.res +0 -1
- package/tests/plugin/PluginSpecExperiment.res.mjs +12 -14
- package/tests/plugin/PluginStructureTest.res +188 -1
- package/tests/plugin/PluginStructureTest.res.mjs +293 -102
- package/tests/plugin/Plugin_EventQuerySchemaTest.res.mjs +3 -3
- package/tests/plugin/SchemaWalkerTest.res +0 -1
- package/tests/plugin/SchemaWalkerTest.res.mjs +17 -19
- package/tests/plugin/StateChangeSlice/PsAttachInvoice.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsChangePhoto.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsDispatchShipment.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsGatedCommands.res.mjs +9 -9
- package/tests/plugin/StateChangeSlice/PsPlaceOrder.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsReserveStock.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsShipOrder.res.mjs +15 -15
- package/tests/plugin/StateChangeSlice/PsTypoStore.res +31 -0
- package/tests/plugin/StateChangeSlice/PsTypoStore.res.mjs +62 -0
- package/tests/plugin/StateChangeSlice/PsUploadAvatar.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsUploadImages.res +40 -0
- package/tests/plugin/StateChangeSlice/PsUploadImages.res.mjs +66 -0
- package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +13 -12
- package/tests/plugin/StateViewSlice/PsAvailableProductsView.res.mjs +8 -8
- package/tests/plugin/StateViewSlice/PsCategoriesView.res.mjs +6 -6
- package/tests/plugin/StateViewSlice/PsCustomersView.res.mjs +10 -10
- package/tests/plugin/StateViewSlice/PsGatedView.res.mjs +6 -6
- package/tests/plugin/StateViewSlice/PsOrdersView.res.mjs +9 -9
- package/tests/plugin/StateViewSlice/PsShipmentsView.res.mjs +11 -10
- package/tests/plugin/pluginDefinitionRequiredScalars.txt +15 -0
- package/tests/querydb/QueryDbFixtures.res +0 -1
- package/tests/querydb/QueryDbFixtures.res.mjs +5 -7
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res +0 -1
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +4 -6
- package/tests/util/CommandPublisherTest.res +0 -1
- package/tests/util/CommandPublisherTest.res.mjs +4 -6
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as Sury from "sury";
|
|
4
5
|
import * as Uuid from "uuid";
|
|
5
6
|
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
6
7
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
@@ -10,20 +11,18 @@ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_excep
|
|
|
10
11
|
import * as Message$ReventlessCore from "../../Message.res.mjs";
|
|
11
12
|
import * as EffectLogger$ReventlessCore from "../../util/EffectLogger.res.mjs";
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
S.literal("Success"),
|
|
17
|
-
S.literal("Failure")
|
|
14
|
+
let auditStatusSchema = Sury.union([
|
|
15
|
+
Sury.literal("Success"),
|
|
16
|
+
Sury.literal("Failure")
|
|
18
17
|
]);
|
|
19
18
|
|
|
20
|
-
let auditRowSchema =
|
|
21
|
-
input: s.m(
|
|
19
|
+
let auditRowSchema = Sury.$schema(s => ({
|
|
20
|
+
input: s.m(Sury.string),
|
|
22
21
|
status: s.m(auditStatusSchema),
|
|
23
|
-
targetIds: s.m(
|
|
24
|
-
commandCount: s.m(
|
|
25
|
-
error: s.m(
|
|
26
|
-
receivedAt: s.m(
|
|
22
|
+
targetIds: s.m(Sury.$option(Sury.array(Sury.string))),
|
|
23
|
+
commandCount: s.m(Sury.$option(Sury.int)),
|
|
24
|
+
error: s.m(Sury.$option(Sury.string)),
|
|
25
|
+
receivedAt: s.m(Sury.string)
|
|
27
26
|
}));
|
|
28
27
|
|
|
29
28
|
function receiveResultToOutcome(result) {
|
|
@@ -236,4 +235,4 @@ export {
|
|
|
236
235
|
takeAuditRow,
|
|
237
236
|
Make,
|
|
238
237
|
}
|
|
239
|
-
/*
|
|
238
|
+
/* auditStatusSchema Not a pure module */
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
S.enableJson()
|
|
2
1
|
// OutboundTranslationSlice callback — implements the tracked external call pattern.
|
|
3
2
|
//
|
|
4
3
|
// Phase 1 (collect): updates the in-memory TODO list from events (no resolve)
|
|
@@ -144,7 +143,7 @@ module Make = (
|
|
|
144
143
|
| Some(_) => () // Already exists -- skip (idempotent)
|
|
145
144
|
| None =>
|
|
146
145
|
let row: todoRow = {
|
|
147
|
-
item: item->
|
|
146
|
+
item: item->Reventless.Util_Sury.toJson(Spec.outboundItemSchema),
|
|
148
147
|
status: Pending,
|
|
149
148
|
createdAt: now(),
|
|
150
149
|
retryCount: 0,
|
|
@@ -170,7 +169,7 @@ module Make = (
|
|
|
170
169
|
let _ = await pending->Array.reduce(Promise.resolve(), async (prev, (id, row)) => {
|
|
171
170
|
let _ = await prev
|
|
172
171
|
|
|
173
|
-
let item = try row.item->
|
|
172
|
+
let item = try row.item->Reventless.Util_Sury.fromJson(Spec.outboundItemSchema)->Some catch {
|
|
174
173
|
| exn =>
|
|
175
174
|
let errMsg =
|
|
176
175
|
exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown")
|
|
@@ -200,7 +199,7 @@ module Make = (
|
|
|
200
199
|
| Ok(Some((targetId, cmd))) =>
|
|
201
200
|
// Encode command and publish
|
|
202
201
|
let commandJson = try cmd
|
|
203
|
-
->
|
|
202
|
+
->Reventless.Util_Sury.toJson(Spec.inboundCommandSchema)
|
|
204
203
|
->Some catch {
|
|
205
204
|
| exn =>
|
|
206
205
|
let errMsg =
|
|
@@ -1,43 +1,42 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Sury from "sury";
|
|
4
4
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
5
5
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
6
6
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
7
|
import * as Effect from "effect/Effect";
|
|
8
8
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
9
9
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
10
|
+
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
10
11
|
import * as Message$ReventlessCore from "../../Message.res.mjs";
|
|
11
12
|
import * as EffectLogger$ReventlessCore from "../../util/EffectLogger.res.mjs";
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
S.literal("Completed"),
|
|
19
|
-
S.literal("Failed")
|
|
14
|
+
let todoStatusSchema = Sury.union([
|
|
15
|
+
Sury.literal("Pending"),
|
|
16
|
+
Sury.literal("Processing"),
|
|
17
|
+
Sury.literal("Completed"),
|
|
18
|
+
Sury.literal("Failed")
|
|
20
19
|
]);
|
|
21
20
|
|
|
22
|
-
let todoRowSchema =
|
|
23
|
-
item: s.m(
|
|
21
|
+
let todoRowSchema = Sury.$schema(s => ({
|
|
22
|
+
item: s.m(Sury.json),
|
|
24
23
|
status: s.m(todoStatusSchema),
|
|
25
|
-
createdAt: s.m(
|
|
26
|
-
processedAt: s.m(
|
|
27
|
-
completedAt: s.m(
|
|
28
|
-
retryCount: s.m(
|
|
29
|
-
lastError: s.m(
|
|
24
|
+
createdAt: s.m(Sury.string),
|
|
25
|
+
processedAt: s.m(Sury.$option(Sury.string)),
|
|
26
|
+
completedAt: s.m(Sury.$option(Sury.string)),
|
|
27
|
+
retryCount: s.m(Sury.int),
|
|
28
|
+
lastError: s.m(Sury.$option(Sury.string))
|
|
30
29
|
}));
|
|
31
30
|
|
|
32
31
|
function todoRowSchemaFor(itemSchema) {
|
|
33
|
-
return
|
|
32
|
+
return Sury.$schema(s => ({
|
|
34
33
|
item: s.m(itemSchema),
|
|
35
34
|
status: s.m(todoStatusSchema),
|
|
36
|
-
createdAt: s.m(
|
|
37
|
-
processedAt: s.m(
|
|
38
|
-
completedAt: s.m(
|
|
39
|
-
retryCount: s.m(
|
|
40
|
-
lastError: s.m(
|
|
35
|
+
createdAt: s.m(Sury.string),
|
|
36
|
+
processedAt: s.m(Sury.$option(Sury.string)),
|
|
37
|
+
completedAt: s.m(Sury.$option(Sury.string)),
|
|
38
|
+
retryCount: s.m(Sury.int),
|
|
39
|
+
lastError: s.m(Sury.$option(Sury.string))
|
|
41
40
|
}));
|
|
42
41
|
}
|
|
43
42
|
|
|
@@ -53,7 +52,7 @@ function Make(Spec) {
|
|
|
53
52
|
if (match !== undefined) {
|
|
54
53
|
return;
|
|
55
54
|
}
|
|
56
|
-
let row_item =
|
|
55
|
+
let row_item = Util_Sury$Reventless.toJson(param[1], Spec.outboundItemSchema);
|
|
57
56
|
let row_createdAt = new Date().toISOString();
|
|
58
57
|
let row = {
|
|
59
58
|
item: row_item,
|
|
@@ -82,7 +81,7 @@ function Make(Spec) {
|
|
|
82
81
|
await prev;
|
|
83
82
|
let item;
|
|
84
83
|
try {
|
|
85
|
-
item = Primitive_option.some(
|
|
84
|
+
item = Primitive_option.some(Util_Sury$Reventless.fromJson(row.item, Spec.outboundItemSchema));
|
|
86
85
|
} catch (raw_exn) {
|
|
87
86
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
88
87
|
let errMsg = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "unknown");
|
|
@@ -112,7 +111,7 @@ function Make(Spec) {
|
|
|
112
111
|
if (match !== undefined) {
|
|
113
112
|
let commandJson;
|
|
114
113
|
try {
|
|
115
|
-
commandJson =
|
|
114
|
+
commandJson = Util_Sury$Reventless.toJson(match[1], Spec.inboundCommandSchema);
|
|
116
115
|
} catch (raw_exn$2) {
|
|
117
116
|
let exn$2 = Primitive_exceptions.internalToException(raw_exn$2);
|
|
118
117
|
let errMsg$1 = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn$2), Stdlib_JsExn.message), "unknown");
|
|
@@ -183,4 +182,4 @@ export {
|
|
|
183
182
|
todoRowSchemaFor,
|
|
184
183
|
Make,
|
|
185
184
|
}
|
|
186
|
-
/*
|
|
185
|
+
/* todoStatusSchema Not a pure module */
|
|
@@ -25,7 +25,7 @@ module Make = (Spec: Spec): T => {
|
|
|
25
25
|
->JSON.Decode.object
|
|
26
26
|
->Option.flatMap(eventObj' => {
|
|
27
27
|
let metaJson = eventObj'->Dict.get("meta")
|
|
28
|
-
switch metaJson->Option.map(meta => meta->
|
|
28
|
+
switch metaJson->Option.map(meta => meta->Reventless.Util_Sury.fromJson(Message.metaSchema)) {
|
|
29
29
|
| Some(eventMeta) =>
|
|
30
30
|
let entry =
|
|
31
31
|
sideEffectsWithTags->Array.find(((module(SideEffect: Reventless.SideEffect.T), _)) =>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as S from "sury/src/S.res.mjs";
|
|
4
3
|
import * as Effect from "@reventlessdev/rescript-effect/src/Effect.res.mjs";
|
|
5
4
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
6
5
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
@@ -10,6 +9,7 @@ import * as Stream from "effect/Stream";
|
|
|
10
9
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
11
10
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
12
11
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
12
|
+
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
13
13
|
import * as Message$ReventlessCore from "../../Message.res.mjs";
|
|
14
14
|
import * as LogFormat$ReventlessCore from "../../util/LogFormat.res.mjs";
|
|
15
15
|
import * as Util_Error$ReventlessCore from "../../util/Util_Error.res.mjs";
|
|
@@ -24,7 +24,7 @@ function Make(Spec) {
|
|
|
24
24
|
let metaJson = eventObj$p["meta"];
|
|
25
25
|
let eventMeta;
|
|
26
26
|
try {
|
|
27
|
-
eventMeta = Stdlib_Option.map(metaJson, meta =>
|
|
27
|
+
eventMeta = Stdlib_Option.map(metaJson, meta => Util_Sury$Reventless.fromJson(meta, Message$ReventlessCore.metaSchema));
|
|
28
28
|
} catch (raw_err) {
|
|
29
29
|
let err = Primitive_exceptions.internalToException(raw_err);
|
|
30
30
|
let errMsg = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(err), Stdlib_JsExn.message), "unknown");
|
|
@@ -92,4 +92,4 @@ function Make(Spec) {
|
|
|
92
92
|
export {
|
|
93
93
|
Make,
|
|
94
94
|
}
|
|
95
|
-
/*
|
|
95
|
+
/* Effect Not a pure module */
|
|
@@ -39,7 +39,7 @@ module Make = (
|
|
|
39
39
|
// fields entirely, while the consumer side (DcbDecode) parses with the sury
|
|
40
40
|
// schema — a js_nullable option field would reject the missing key and the
|
|
41
41
|
// event would be dropped as schema drift.
|
|
42
|
-
let json = event->
|
|
42
|
+
let json = event->Reventless.Util_Sury.toJson(Spec.eventSchema)
|
|
43
43
|
let (eventType, data) = json->Message.splitMessage
|
|
44
44
|
// Use `extractTagsExpanded` (not `extractTags`) so per-element tags on
|
|
45
45
|
// `array<string>` fields are emitted — e.g. OrderPlaced's
|
|
@@ -433,7 +433,7 @@ module Make = (
|
|
|
433
433
|
| Error(error) =>
|
|
434
434
|
// Business-rule rejection — no append, but the read snapshot is valid; cache it.
|
|
435
435
|
cachePut((state, headPosition))
|
|
436
|
-
let errorJson = error->
|
|
436
|
+
let errorJson = error->Reventless.Util_Sury.toJson(Spec.errorSchema)
|
|
437
437
|
let errorCode = errorJson->Message.variantNameOfJson
|
|
438
438
|
let (_, payloadDict) = errorJson->Message.splitMessage
|
|
439
439
|
let errorDetail =
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as S from "sury/src/S.res.mjs";
|
|
4
3
|
import * as Stream from "@reventlessdev/rescript-effect/src/Stream.res.mjs";
|
|
5
4
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
6
5
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
@@ -11,6 +10,7 @@ import * as Stream$1 from "effect/Stream";
|
|
|
11
10
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
12
11
|
import * as Lru$ReventlessCore from "../../util/Lru.res.mjs";
|
|
13
12
|
import * as DcbDecode$Reventless from "@reventlessdev/reventless-spec/src/components/DcbDecode.res.mjs";
|
|
13
|
+
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
14
14
|
import * as Message$ReventlessCore from "../../Message.res.mjs";
|
|
15
15
|
import * as Metrics$ReventlessCore from "../../util/Metrics.res.mjs";
|
|
16
16
|
import * as LogFormat$ReventlessCore from "../../util/LogFormat.res.mjs";
|
|
@@ -186,7 +186,7 @@ function Make(Spec) {
|
|
|
186
186
|
}
|
|
187
187
|
let rawEvents = newEvents$1.map(e => {
|
|
188
188
|
let parentMeta = command$p.meta;
|
|
189
|
-
let json =
|
|
189
|
+
let json = Util_Sury$Reventless.toJson(e, Spec.eventSchema);
|
|
190
190
|
let match = Message$ReventlessCore.splitMessage(json);
|
|
191
191
|
let eventType = match[0];
|
|
192
192
|
let baseTags = DcbTag$Reventless.extractTagsExpanded(Spec.eventSchema, e);
|
|
@@ -272,7 +272,7 @@ function Make(Spec) {
|
|
|
272
272
|
state,
|
|
273
273
|
headPosition
|
|
274
274
|
]);
|
|
275
|
-
let errorJson =
|
|
275
|
+
let errorJson = Util_Sury$Reventless.toJson(newEvents._0, Spec.errorSchema);
|
|
276
276
|
let errorCode = Message$ReventlessCore.variantNameOfJson(errorJson);
|
|
277
277
|
let match = Message$ReventlessCore.splitMessage(errorJson);
|
|
278
278
|
let payloadDict = match[1];
|
|
@@ -321,4 +321,4 @@ function Make(Spec) {
|
|
|
321
321
|
export {
|
|
322
322
|
Make,
|
|
323
323
|
}
|
|
324
|
-
/*
|
|
324
|
+
/* Stream Not a pure module */
|
|
@@ -103,7 +103,7 @@ module Make = (
|
|
|
103
103
|
// fall back defensively so a malformed envelope never drops the event.
|
|
104
104
|
let meta = switch envelopeDict->Dict.get("meta") {
|
|
105
105
|
| Some(m) =>
|
|
106
|
-
switch m->
|
|
106
|
+
switch m->Reventless.Util_Sury.fromJson(Message.metaSchema) {
|
|
107
107
|
| parsed => parsed
|
|
108
108
|
| exception _ => Message.generateMeta(~service=Spec.name)
|
|
109
109
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as S from "sury/src/S.res.mjs";
|
|
4
3
|
import * as Stream from "@reventlessdev/rescript-effect/src/Stream.res.mjs";
|
|
5
4
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
6
5
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
@@ -12,6 +11,7 @@ import * as Effect from "effect/Effect";
|
|
|
12
11
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
13
12
|
import * as DcbDecode$Reventless from "@reventlessdev/reventless-spec/src/components/DcbDecode.res.mjs";
|
|
14
13
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
14
|
+
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
15
15
|
import * as Message$ReventlessCore from "../../Message.res.mjs";
|
|
16
16
|
import * as Component$ReventlessCore from "../Component.res.mjs";
|
|
17
17
|
import * as LogFormat$ReventlessCore from "../../util/LogFormat.res.mjs";
|
|
@@ -87,7 +87,7 @@ function Make(RuntimeEnvironment) {
|
|
|
87
87
|
let meta;
|
|
88
88
|
if (m !== undefined) {
|
|
89
89
|
try {
|
|
90
|
-
meta =
|
|
90
|
+
meta = Util_Sury$Reventless.fromJson(m, Message$ReventlessCore.metaSchema);
|
|
91
91
|
} catch (exn) {
|
|
92
92
|
meta = Message$ReventlessCore.generateMeta(Spec.name, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
93
93
|
}
|
|
@@ -158,4 +158,4 @@ export {
|
|
|
158
158
|
FrameworkProjection,
|
|
159
159
|
Make,
|
|
160
160
|
}
|
|
161
|
-
/*
|
|
161
|
+
/* Stream Not a pure module */
|
|
@@ -1,32 +1,5 @@
|
|
|
1
1
|
open ReventlessInfra.Api
|
|
2
2
|
|
|
3
|
-
let adminAuth: Reventless.ReadModel.authorization = {
|
|
4
|
-
tableName: "Plugin",
|
|
5
|
-
group: "Admin",
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
// Fields present on `PluginsReadModelSpec.state` for projection/storage purposes
|
|
9
|
-
// but intentionally absent from the public GraphQL surface. Shared with
|
|
10
|
-
// `Platform_Admin_Structure` so the schema announced via `Platform_ComponentDefinitions`
|
|
11
|
-
// stays aligned with the SDL — otherwise AutoUI generates list-view queries
|
|
12
|
-
// for fields the server doesn't expose and every Plugin row fails to load.
|
|
13
|
-
let pluginExcludeFields: array<string> = [
|
|
14
|
-
"eventCollector",
|
|
15
|
-
"extensionPointNames",
|
|
16
|
-
"extensionNames",
|
|
17
|
-
]
|
|
18
|
-
|
|
19
|
-
// Additional fields the SDL exposes but the Plugin list view should NOT
|
|
20
|
-
// surface — they're option-of-nested-object types (e.g. apiSchemaFragment,
|
|
21
|
-
// structure) which AutoUI currently renders as scalar columns
|
|
22
|
-
// and queries without a sub-selection, failing schema validation. Other
|
|
23
|
-
// callers (host-shell's Platform_ComponentDefinitions) keep querying them via
|
|
24
|
-
// dedicated fields and resolver paths.
|
|
25
|
-
let pluginUIOnlyExcludeFields: array<string> = pluginExcludeFields->Array.concat([
|
|
26
|
-
"apiSchemaFragment",
|
|
27
|
-
"structure",
|
|
28
|
-
])
|
|
29
|
-
|
|
30
3
|
// Admin read-model query entries are generated from each spec the same way
|
|
31
4
|
// ordinary read models are (Plugin_Builder.res): `subIdField` flows from the
|
|
32
5
|
// spec's `subIdConfig` and `indexQueries` from `config.indexes`, so
|
|
@@ -57,8 +30,18 @@ let queryEntries: array<querySchemaEntry> = [
|
|
|
57
30
|
listFieldName: Api_Naming.adminField(~name="Plugins"),
|
|
58
31
|
returnTypeName: Api_Naming.adminField(~name="Plugin"),
|
|
59
32
|
stateSchema: PluginsReadModelSpec.stateSchema->S.castToUnknown,
|
|
60
|
-
|
|
61
|
-
|
|
33
|
+
// Read off the spec rather than restated. The hand-written
|
|
34
|
+
// `{tableName: "Plugin", group: "Admin"}` that used to sit here said the same
|
|
35
|
+
// thing as `Spec.authorization` in a different type, and the spec's default
|
|
36
|
+
// (`AllowAuthenticated`) disagreed with it — so the view's rule depended on
|
|
37
|
+
// which of the two a reader happened to find. The `tableName` half was never
|
|
38
|
+
// read: the entry path uses only the group, and the per-`@index` auth-table
|
|
39
|
+
// pipeline params come from `indexConfig.authorization`, which is untouched.
|
|
40
|
+
authorization: None,
|
|
41
|
+
permission: PluginsReadModelSpec.authorization,
|
|
42
|
+
// No `excludeFields`: the three fields this entry used to name are declared
|
|
43
|
+
// `@internal` on the spec, and `deriveObjectTypeWithNested` reads that off the
|
|
44
|
+
// schema itself.
|
|
62
45
|
subIdField: ?PluginsReadModelSpec.subIdConfig->Option.map((c: Reventless.ReadModel.subIdConfig<_>) => c.subIdField),
|
|
63
46
|
indexQueries: ?indexQueriesOfConfig(PluginsReadModelSpec.config),
|
|
64
47
|
},
|
|
@@ -7,22 +7,6 @@ import * as PluginSpec$ReventlessCore from "../lifecycle/PluginSpec.res.mjs";
|
|
|
7
7
|
import * as ApiNoApiHelpers$ReventlessCore from "../../components/Api/ApiNoApiHelpers.res.mjs";
|
|
8
8
|
import * as PluginsReadModelSpec$ReventlessCore from "../lifecycle/PluginsReadModelSpec.res.mjs";
|
|
9
9
|
|
|
10
|
-
let adminAuth = {
|
|
11
|
-
tableName: "Plugin",
|
|
12
|
-
group: "Admin"
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
let pluginExcludeFields = [
|
|
16
|
-
"eventCollector",
|
|
17
|
-
"extensionPointNames",
|
|
18
|
-
"extensionNames"
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
let pluginUIOnlyExcludeFields = pluginExcludeFields.concat([
|
|
22
|
-
"apiSchemaFragment",
|
|
23
|
-
"structure"
|
|
24
|
-
]);
|
|
25
|
-
|
|
26
10
|
function indexQueriesOfConfig(config) {
|
|
27
11
|
if (config.indexes.length !== 0) {
|
|
28
12
|
return config.indexes;
|
|
@@ -35,8 +19,8 @@ let queryEntries = [{
|
|
|
35
19
|
returnTypeName: Api_Naming$ReventlessCore.adminField("Plugin"),
|
|
36
20
|
stateSchema: PluginsReadModelSpec$ReventlessCore.stateSchema,
|
|
37
21
|
specName: PluginsReadModelSpec$ReventlessCore.name,
|
|
38
|
-
authorization:
|
|
39
|
-
|
|
22
|
+
authorization: undefined,
|
|
23
|
+
permission: PluginsReadModelSpec$ReventlessCore.authorization,
|
|
40
24
|
subIdField: Stdlib_Option.map(undefined, c => c.subIdField),
|
|
41
25
|
indexQueries: indexQueriesOfConfig(PluginsReadModelSpec$ReventlessCore.config)
|
|
42
26
|
}];
|
|
@@ -53,11 +37,8 @@ let pluginAggregateMutationEntries = fieldNames.length === 0 ? [] : [{
|
|
|
53
37
|
}];
|
|
54
38
|
|
|
55
39
|
export {
|
|
56
|
-
adminAuth,
|
|
57
|
-
pluginExcludeFields,
|
|
58
|
-
pluginUIOnlyExcludeFields,
|
|
59
40
|
indexQueriesOfConfig,
|
|
60
41
|
queryEntries,
|
|
61
42
|
pluginAggregateMutationEntries,
|
|
62
43
|
}
|
|
63
|
-
/*
|
|
44
|
+
/* queryEntries Not a pure module */
|
|
@@ -55,7 +55,7 @@ let scanSchema = (~component: string, schema: S.t<unknown>): array<warning> => {
|
|
|
55
55
|
| _ => []
|
|
56
56
|
}
|
|
57
57
|
switch schema {
|
|
58
|
-
|
|
|
58
|
+
| AnyOf({anyOf}) => anyOf->Array.flatMap(fromVariant)
|
|
59
59
|
| other => fromVariant(other)
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -66,3 +66,120 @@ let message = (w: warning): string =>
|
|
|
66
66
|
`${w.component}.${w.field} looks like a stored-object reference but declares no store — ` ++
|
|
67
67
|
`annotate it \`@storageRef("<store>")\` so the deployment provisions the store it needs, ` ++
|
|
68
68
|
`or rename the field if it holds an external URL. Heuristic matches are never provisioned.`
|
|
69
|
+
|
|
70
|
+
// ── Near-duplicate stores ──────────────────────────────────────────────────
|
|
71
|
+
//
|
|
72
|
+
// Under name-derived stores a typo does not fail, it *provisions*: `productImage`
|
|
73
|
+
// and `productImgae` both compile, both deploy, and objects split silently
|
|
74
|
+
// across two buckets. Nothing else in the pipeline can see the mistake — both
|
|
75
|
+
// are well-formed declarations — so the check has to live where every store a
|
|
76
|
+
// plugin declares is visible at once.
|
|
77
|
+
//
|
|
78
|
+
// Unlike the heuristic lint above this is a hard failure, and it is meant to be:
|
|
79
|
+
// a warning about infrastructure that was already created is a warning nobody
|
|
80
|
+
// can act on cheaply. A pair that is genuinely two stores settles it by naming
|
|
81
|
+
// one explicitly with `@storageRef("<store>")`.
|
|
82
|
+
|
|
83
|
+
/** Two store declarations close enough that one is likely a typo for the other. */
|
|
84
|
+
type collision = {
|
|
85
|
+
a: Reventless.Plugin.requiredStoreDeclaration,
|
|
86
|
+
b: Reventless.Plugin.requiredStoreDeclaration,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Exactly the optimal-string-alignment distance ≤ 1: one insert, one delete, one
|
|
90
|
+
// substitution, or one transposition. Written directly rather than as a general
|
|
91
|
+
// distance because a transposition is the shape the motivating typo has
|
|
92
|
+
// (`Images` → `Imgaes`), and a plain Levenshtein scores that 2 and misses it.
|
|
93
|
+
let withinOneEdit = (a: string, b: string): bool => {
|
|
94
|
+
let (la, lb) = (String.length(a), String.length(b))
|
|
95
|
+
let charAt = (s, i) => String.charAt(s, i)
|
|
96
|
+
if la == lb {
|
|
97
|
+
let diffs = []
|
|
98
|
+
for i in 0 to la - 1 {
|
|
99
|
+
if charAt(a, i) != charAt(b, i) {
|
|
100
|
+
diffs->Array.push(i)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
switch diffs {
|
|
104
|
+
| [] => true
|
|
105
|
+
| [_] => true
|
|
106
|
+
| [i, j] if j == i + 1 =>
|
|
107
|
+
charAt(a, i) == charAt(b, j) && charAt(a, j) == charAt(b, i)
|
|
108
|
+
| _ => false
|
|
109
|
+
}
|
|
110
|
+
} else if la - lb == 1 || lb - la == 1 {
|
|
111
|
+
// The longer string with one character removed must equal the shorter one.
|
|
112
|
+
let (long, short) = la > lb ? (a, b) : (b, a)
|
|
113
|
+
let rec scan = (~li, ~si, ~skipped) =>
|
|
114
|
+
if si >= String.length(short) {
|
|
115
|
+
true
|
|
116
|
+
} else if charAt(long, li) == charAt(short, si) {
|
|
117
|
+
scan(~li=li + 1, ~si=si + 1, ~skipped)
|
|
118
|
+
} else if skipped {
|
|
119
|
+
false
|
|
120
|
+
} else {
|
|
121
|
+
scan(~li=li + 1, ~si, ~skipped=true)
|
|
122
|
+
}
|
|
123
|
+
scan(~li=0, ~si=0, ~skipped=false)
|
|
124
|
+
} else {
|
|
125
|
+
false
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Whether two store names are the same word in different number. Reached only
|
|
130
|
+
through an explicit `@storageRef` override — a derived name is already
|
|
131
|
+
pluralised through its singular stem, so two *derived* names cannot differ
|
|
132
|
+
this way. */
|
|
133
|
+
let sameStem = (a: string, b: string): bool =>
|
|
134
|
+
Api_Naming.singularize(a) == Api_Naming.singularize(b)
|
|
135
|
+
|
|
136
|
+
// The unqualified store name and its owning plugin, split off the qualified key
|
|
137
|
+
// the declarations carry.
|
|
138
|
+
let splitKey = (key: string): (string, string) =>
|
|
139
|
+
switch key->String.split(".") {
|
|
140
|
+
| [plugin, store] => (plugin, store)
|
|
141
|
+
| _ => ("", key)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
Pairs of declared stores that are probably one store misspelled twice.
|
|
146
|
+
|
|
147
|
+
Compared within an owning plugin only: two plugins may legitimately hold stores
|
|
148
|
+
whose names are one edit apart, and neither can be a typo for the other.
|
|
149
|
+
*/
|
|
150
|
+
let collisions = (
|
|
151
|
+
declarations: array<Reventless.Plugin.requiredStoreDeclaration>,
|
|
152
|
+
): array<collision> => {
|
|
153
|
+
// One entry per store, keeping the first declaration site as the one the
|
|
154
|
+
// message names — several fields naming one store is ordinary, not a clash.
|
|
155
|
+
let byStore: dict<Reventless.Plugin.requiredStoreDeclaration> = Dict.make()
|
|
156
|
+
declarations->Array.forEach(d =>
|
|
157
|
+
switch byStore->Dict.get(d.store) {
|
|
158
|
+
| Some(_) => ()
|
|
159
|
+
| None => byStore->Dict.set(d.store, d)
|
|
160
|
+
}
|
|
161
|
+
)
|
|
162
|
+
let unique = byStore->Dict.valuesToArray
|
|
163
|
+
let found = []
|
|
164
|
+
for i in 0 to Array.length(unique) - 1 {
|
|
165
|
+
for j in i + 1 to Array.length(unique) - 1 {
|
|
166
|
+
let a = unique->Array.getUnsafe(i)
|
|
167
|
+
let b = unique->Array.getUnsafe(j)
|
|
168
|
+
let (pluginA, storeA) = splitKey(a.store)
|
|
169
|
+
let (pluginB, storeB) = splitKey(b.store)
|
|
170
|
+
if pluginA == pluginB && (withinOneEdit(storeA, storeB) || sameStem(storeA, storeB)) {
|
|
171
|
+
found->Array.push({a, b})->ignore
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
found
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** The failure text: name both stores and both declaration sites, so a pair that
|
|
179
|
+
is genuinely two stores is diagnosed in one reading. */
|
|
180
|
+
let collisionMessage = (c: collision): string =>
|
|
181
|
+
`${c.a.store} (${c.a.component}.${c.a.field}) and ${c.b.store} ` ++
|
|
182
|
+
`(${c.b.component}.${c.b.field}) differ by one edit — one is probably a typo for ` ++
|
|
183
|
+
`the other, and both would be provisioned, splitting objects across two stores. ` ++
|
|
184
|
+
`Fix the field name, or name the store explicitly with \`@storageRef("<store>")\` ` ++
|
|
185
|
+
`if the two really are separate stores.`
|