@reventlessdev/reventless-core 3.0.0-alpha.260 → 3.0.0-alpha.262
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 +24 -0
- package/package.json +10 -10
- package/src/Behavior.res +1 -4
- package/src/Message.res +17 -14
- package/src/Projection.res +51 -25
- package/src/RequestContext.res +8 -9
- package/src/ResourceAttribution.res +28 -14
- package/src/adapter/Adapter.res +48 -4
- package/src/adapter/EventLogProvisioning/EventLogProvisioning.res +5 -5
- package/src/adapter/Messaging/Messaging_Log_Backend.res +10 -7
- package/src/adapter/Messaging/Messaging_Log_Backend.res.mjs +2 -4
- package/src/adapter/Monitoring/Monitoring.res +16 -17
- package/src/adapter/QueryInterception/QueryInterception.res +0 -1
- package/src/adapter/Runtime/AggregateRuntime_Builder_Common.res +12 -5
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +11 -7
- package/src/adapter/Runtime/PluginRuntime_Builder_Micro.res +1 -7
- package/src/adapter/Runtime/PluginRuntime_Builder_Single.res +1 -7
- package/src/adapter/RuntimeExtension/RuntimeExtension.res +0 -1
- package/src/adapter/Secrets/Secrets_Node_Backend.res +60 -0
- package/src/adapter/Secrets/Secrets_Node_Backend.res.mjs +69 -0
- package/src/admin/Platform_Admin.res +17 -6
- package/src/admin/Platform_AdminApi.res +14 -9
- package/src/admin/Platform_Admin_Callback.res +1 -1
- package/src/admin/Platform_BakedManifest.res +34 -34
- package/src/admin/Platform_ComponentDefinitionsApi.res +9 -21
- package/src/admin/Platform_PluginStructuresApi.res +15 -12
- package/src/admin/UiFragmentRegistry/StateChange/UiFragmentRegistry.res +1 -1
- package/src/components/Aggregate/Aggregate.res +13 -12
- package/src/components/Aggregate/Aggregate_Builder.res +22 -21
- package/src/components/Aggregate/Aggregate_Callback.res +91 -86
- package/src/components/Api/ApiNoApiHelpers.res +1 -3
- package/src/components/Api/Api_Ids.res +0 -1
- package/src/components/Api/Api_Naming.res +41 -18
- package/src/components/Api/GraphQL_FragmentGenerator.res +38 -51
- package/src/components/Api/GraphQL_SchemaInspector.res +5 -3
- package/src/components/Api/GraphQL_Stitcher.res +9 -10
- package/src/components/Api/MCP_SchemaGenerator.res +8 -12
- package/src/components/Api/OwnerScopeDiagnostics.res +1 -2
- package/src/components/Api/QueryDbListQuery.res +13 -6
- package/src/components/Api/SchemaType.res +28 -23
- package/src/components/Api/SuryToJsonSchema.res +9 -10
- package/src/components/AutomationSlice/AutomationSlice.res +4 -4
- package/src/components/AutomationSlice/AutomationSlice_Builder.res +15 -14
- package/src/components/AutomationSlice/AutomationSlice_Callback.res +3 -3
- package/src/components/Builder_Helpers.res +12 -23
- package/src/components/CommandGenerator/CommandGenerator.res +6 -1
- package/src/components/CommandGenerator/CommandGenerator_Builder.res +29 -21
- package/src/components/CommandGenerator/CommandGenerator_Callback.res +17 -21
- package/src/components/CommandTopic/CommandTopic.res +3 -3
- package/src/components/CommandTopic/CommandTopic_Builder.res +10 -10
- package/src/components/CommandTopic/CommandTopic_Callback.res +1 -4
- package/src/components/CommandTopic/CommandTopic_Helpers.res +1 -2
- package/src/components/Counter/Counter_Builder.res +1 -6
- package/src/components/Counter/Counter_Callback.res +3 -3
- package/src/components/Dcb/Dcb_Builder.res +970 -956
- package/src/components/DcbEventLog/DcbEventLog.res +4 -4
- package/src/components/DcbEventLog/DcbEventLog_Builder.res +0 -1
- package/src/components/DcbEventLog/DcbEventLog_Operations.res +17 -18
- package/src/components/EventCollector/EventCollector_Builder.res +2 -1
- package/src/components/EventLog/EventLog.res +5 -1
- package/src/components/EventLog/EventLog_Operations.res +12 -8
- package/src/components/EventMapper/EventMapper.res +8 -10
- package/src/components/EventMapper/EventMapper_Builder.res +4 -1
- package/src/components/EventMapper/EventMapper_Callback.res +46 -31
- package/src/components/EventTopic/EventTopic.res +3 -3
- package/src/components/EventTopic/EventTopic_Builder.res +1 -1
- package/src/components/Extension/Extension.res +4 -1
- package/src/components/Extension/Extension_Operations.res +11 -3
- package/src/components/ExtensionPoint/ExtensionPoint.res +3 -3
- package/src/components/ExtensionPoint/ExtensionPoint_Builder.res +9 -10
- package/src/components/ExtensionPoint/ExtensionPoint_Callback.res +2 -6
- package/src/components/ExtensionPoint/ExtensionPoint_Operations.res +13 -5
- package/src/components/Heartbeat/Heartbeat_Callback.res +3 -3
- package/src/components/InboundTranslationSlice/InboundTranslationSlice.res +4 -4
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Builder.res +7 -10
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice.res +4 -4
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res +15 -14
- package/src/components/QueryDb/QueryDb_Adapter.res +1 -3
- package/src/components/QueryDb/QueryDb_Operations.res +10 -10
- package/src/components/ReadModel/ReadModel.res +3 -3
- package/src/components/ReadModel/ReadModel_Builder.res +1 -2
- package/src/components/ReadModel/ReadModel_Callback.res +2 -1
- package/src/components/SideEffectHandler/SideEffectHandler_Callback.res +5 -2
- package/src/components/StateChangeSlice/StateChangeSlice.res +3 -3
- package/src/components/StateChangeSlice/StateChangeSlice_Builder.res +23 -4
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +22 -6
- package/src/components/StateTopic.res +1 -3
- package/src/components/StateViewSlice/StateViewSlice.res +4 -4
- package/src/components/StateViewSlice/StateViewSlice_Builder.res +79 -68
- package/src/components/StateViewSlice/StateViewSlice_Callback.res +3 -1
- package/src/components/Task/Task.res +3 -3
- package/src/components/Task/Task_Adapter.res +4 -1
- package/src/components/Task/Task_Builder.res +24 -21
- package/src/plugin/api/PluginBaseFragment.res +9 -3
- package/src/plugin/component/Capability_Inference.res +8 -10
- package/src/plugin/component/Plugin.res +6 -6
- package/src/plugin/component/Plugin_Builder.res +54 -50
- package/src/plugin/component/Plugin_Callback.res +10 -6
- package/src/plugin/component/Plugin_Helpers.res +264 -230
- package/src/plugin/component/Plugin_Structure.res +370 -324
- package/src/plugin/component/Plugin_SubscriptionSchema.res +8 -6
- package/src/plugin/component/SchemaWalker.res +11 -12
- package/src/plugin/connect/PluginConnectExtension_Mapping.res +45 -50
- package/src/plugin/lifecycle/PluginBehavior.res +3 -4
- package/src/plugin/lifecycle/PluginSpec.res +1 -2
- package/src/plugin/lifecycle/PluginsProjection.res +16 -5
- package/src/plugin/lifecycle/PluginsReadModelSpec.res +0 -2
- package/src/util/CommandPublisher.res +9 -2
- package/src/util/CsvStream.res +3 -3
- package/src/util/Interstack.res +7 -15
- package/src/util/Interstack.resi +3 -3
- package/src/util/LogFormat.res +5 -9
- package/src/util/Logger.res +1 -2
- package/src/util/Lru.res +2 -1
- package/src/util/Lru.resi +2 -3
- package/src/util/ScheduleOps.res +24 -27
- package/src/util/StorePrefixCollision.res +6 -9
- package/src/util/Util_Promise.res +4 -1
- package/src/util/Util_Promise.res.mjs +1 -1
- package/tests/IdentityTest.res +166 -113
- package/tests/ResourceAttributionTest.res +28 -25
- package/tests/Secrets_Node_BackendTest.res +141 -0
- package/tests/Secrets_Node_BackendTest.res.mjs +152 -0
- package/tests/StorePrefixCollisionTest.res +2 -1
- package/tests/TaskBucketNamingTest.res +3 -2
- package/tests/adapter/EventLogProvisioningTest.res +51 -48
- package/tests/adapter/MonitoringTest.res +81 -38
- package/tests/adapter/QueryInterceptionTest.res +2 -2
- package/tests/adapter/RefusalVocabularyTest.res +31 -23
- package/tests/adapter/RuntimeExtensionHookReachTest.res +9 -8
- package/tests/adapter/RuntimeExtensionTest.res +5 -3
- package/tests/admin/AdminApiSchemaDriftTest.res +22 -16
- package/tests/admin/Platform_Admin_StructureTest.res +22 -14
- package/tests/admin/Platform_Admin_StructureTest.res.mjs +4 -3
- package/tests/admin/Platform_BakedManifestTest.res +31 -35
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +18 -15
- package/tests/admin/Platform_PluginStructuresApiTest.res +5 -3
- package/tests/admin/Platform_UIFragmentsApiTest.res +6 -3
- package/tests/aggregate/AggregateCacheTest.res +10 -12
- package/tests/aggregate/AggregateCallbackTest.res +75 -46
- package/tests/aggregate/AggregateCausationTest.res +19 -20
- package/tests/aggregate/AggregateConflictTest.res +41 -19
- package/tests/aggregate/AggregateFixtures.res +15 -5
- package/tests/aggregate/AggregateRejectionTest.res +97 -80
- package/tests/aggregate/AggregateSnapshotTest.res +44 -16
- package/tests/api/Api_IdsTest.res +10 -4
- package/tests/api/BrandedMarkerCompositionTest.res +48 -36
- package/tests/api/GeolocationSemanticTest.res +3 -3
- package/tests/api/GraphQL_FragmentGeneratorTest.res +66 -54
- package/tests/api/OwnerScopeDiagnosticsTest.res +31 -27
- package/tests/api/StorageRefFieldsTest.res +30 -18
- package/tests/api/SuryToJsonSchemaTest.res +1315 -1014
- package/tests/api/TaggedUnionSchemaTest.res +17 -24
- package/tests/commandgenerator/CommandGeneratorCallbackTest.res +235 -179
- package/tests/commandgenerator/CommandGeneratorFixtures.res +8 -13
- package/tests/commandgenerator/OwnerStampingTest.res +91 -76
- package/tests/commandtopic/CommandOutcomeHookTest.res +198 -155
- package/tests/commandtopic/CommandTopicCallbackFixtures.res +5 -4
- package/tests/commandtopic/CommandTopicCallbackTest.res +61 -43
- package/tests/commandtopic/CommandTopicHelpersRejectionTest.res +70 -55
- package/tests/counter/CounterCallbackTest.res +40 -34
- package/tests/counter/CounterFixtures.res +4 -4
- package/tests/dcb/DcbDecodeTest.res +115 -84
- package/tests/dcb/DcbEventLogOperationsTest.res +194 -143
- package/tests/dcb/DcbEventLogSchemaTest.res +13 -13
- package/tests/dcb/DcbFixtures.res +4 -5
- package/tests/dcb/DcbScopeInferenceTest.res +173 -114
- package/tests/dcb/DcbStateChangeSliceTest.res +391 -262
- package/tests/dcb/DcbTagTest.res +22 -11
- package/tests/dcb/DcbValidationTest.res +288 -218
- package/tests/eventlog/EventLogFixtures.res +4 -4
- package/tests/eventlog/EventLogOperationsTest.res +102 -67
- package/tests/eventlog/EventLogRetryTest.res +104 -65
- package/tests/eventmapper/EventMapperCallbackTest.res +118 -83
- package/tests/eventmapper/EventMapperFixtures.res +15 -23
- package/tests/eventmapper/EventMapperTest.res +54 -38
- package/tests/eventtopic/EventTopicFixtures.res +3 -4
- package/tests/eventtopic/EventTopicOperationsTest.res +41 -29
- package/tests/extensionpoint/ExtensionPointCallbackTest.res +58 -45
- package/tests/extensionpoint/ExtensionPointFixtures.res +16 -20
- package/tests/extensionpoint/ExtensionPointOperationsTest.res +70 -49
- package/tests/extensionpoint/PluginDisconnectScheduleTest.res +2 -1
- package/tests/logger/LogFormatTest.res +104 -82
- package/tests/logger/LoggerLazyTest.res +21 -12
- package/tests/message/MessageTest.res +96 -93
- package/tests/message/MetaEnvelopeTest.res +26 -30
- package/tests/plugin/HeartbeatDisconnectGraceTest.res +31 -25
- package/tests/plugin/ManifestVisibilityTest.res +20 -12
- package/tests/plugin/PluginDefinitionScalars.res +1 -2
- package/tests/plugin/PluginLifecycleCorpusTest.res +15 -12
- package/tests/plugin/PluginSpecExperiment.res +0 -1
- package/tests/plugin/PluginStructureTest.res +1529 -1045
- package/tests/plugin/Plugin_EventQuerySchemaTest.res +21 -10
- package/tests/plugin/SchemaWalkerTest.res +116 -70
- package/tests/plugin/StateChange/PsReserveStock.res +4 -4
- package/tests/plugin/StateView/PsAnnotatedView.res +4 -4
- package/tests/plugin/StateView/PsCustomersView.res +4 -4
- package/tests/plugin/StateView/PsShipmentsView.res +3 -2
- package/tests/projection/LifecycleTrailTest.res +1 -4
- package/tests/projection/ProjectionOptimizeTest.res +13 -9
- package/tests/querydb/QueryDbFixtures.res +0 -1
- package/tests/querydb/QueryDbOperationsTest.res +99 -64
- package/tests/querydb/TaggedUnionStampTest.res +10 -8
- package/tests/sideeffecthandler/SideEffectHandlerCallbackTest.res +50 -35
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res +4 -10
- package/tests/util/CommandPublisherTest.res +0 -1
- package/tests/util/CsvStreamTest.res +3 -3
- package/tests/util/LruTest.res +84 -56
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
4
|
+
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
5
|
+
import * as Stdlib_Result from "@rescript/runtime/lib/es6/Stdlib_Result.js";
|
|
6
|
+
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
7
|
+
import * as Secrets$Reventless from "@reventlessdev/reventless-spec/src/semantic/Secrets.res.mjs";
|
|
8
|
+
import * as Capabilities$Reventless from "@reventlessdev/reventless-spec/src/semantic/Capabilities.res.mjs";
|
|
9
|
+
import * as Secrets_Node_Backend$ReventlessCore from "../src/adapter/Secrets/Secrets_Node_Backend.res.mjs";
|
|
10
|
+
|
|
11
|
+
function token(length, alphabet) {
|
|
12
|
+
return Stdlib_Result.getOr(Secrets_Node_Backend$ReventlessCore.provider.randomToken(length, alphabet), "");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
globalThis.describe("randomToken", () => {
|
|
16
|
+
globalThis.test("draws the requested length", () => {
|
|
17
|
+
globalThis.expect([
|
|
18
|
+
1,
|
|
19
|
+
6,
|
|
20
|
+
32,
|
|
21
|
+
64
|
|
22
|
+
].map(length => token(length, "Digits").length)).toEqual([
|
|
23
|
+
1,
|
|
24
|
+
6,
|
|
25
|
+
32,
|
|
26
|
+
64
|
|
27
|
+
]);
|
|
28
|
+
});
|
|
29
|
+
globalThis.test("draws only from the alphabet it was given", () => {
|
|
30
|
+
let allowed = Secrets$Reventless.characters("UrlSafe");
|
|
31
|
+
globalThis.expect(token(512, "UrlSafe").split("").every(c => allowed.includes(c))).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
globalThis.test("digits are digits", () => {
|
|
34
|
+
globalThis.expect(token(512, "Digits").split("").every(c => "0123456789".includes(c))).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
globalThis.test("two draws differ", () => {
|
|
37
|
+
globalThis.expect(token(32, "UrlSafe") === token(32, "UrlSafe")).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
globalThis.test("a non-positive length is refused, not clamped", () => {
|
|
40
|
+
globalThis.expect([
|
|
41
|
+
0,
|
|
42
|
+
-1
|
|
43
|
+
].map(length => Stdlib_Result.isError(Secrets_Node_Backend$ReventlessCore.provider.randomToken(length, "Digits")))).toEqual([
|
|
44
|
+
true,
|
|
45
|
+
true
|
|
46
|
+
]);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
globalThis.describe("accepts — the rejection rule", () => {
|
|
51
|
+
let rejected = size => Stdlib_Array.fromInitializer(256, i => i).filter(byte => !Secrets_Node_Backend$ReventlessCore.accepts(byte, size));
|
|
52
|
+
globalThis.test("rejects exactly the bytes that would skew a 10-character alphabet", () => {
|
|
53
|
+
globalThis.expect(rejected(10)).toEqual([
|
|
54
|
+
250,
|
|
55
|
+
251,
|
|
56
|
+
252,
|
|
57
|
+
253,
|
|
58
|
+
254,
|
|
59
|
+
255
|
|
60
|
+
]);
|
|
61
|
+
});
|
|
62
|
+
globalThis.test("rejects nothing when the alphabet divides evenly", () => {
|
|
63
|
+
globalThis.expect(rejected(64)).toEqual([]);
|
|
64
|
+
});
|
|
65
|
+
globalThis.test("what it accepts is a whole multiple of the alphabet", () => {
|
|
66
|
+
globalThis.expect([
|
|
67
|
+
2,
|
|
68
|
+
3,
|
|
69
|
+
7,
|
|
70
|
+
10,
|
|
71
|
+
16,
|
|
72
|
+
26,
|
|
73
|
+
62,
|
|
74
|
+
64
|
|
75
|
+
].map(size => Primitive_int.mod_(256 - rejected(size).length | 0, size))).toEqual([
|
|
76
|
+
0,
|
|
77
|
+
0,
|
|
78
|
+
0,
|
|
79
|
+
0,
|
|
80
|
+
0,
|
|
81
|
+
0,
|
|
82
|
+
0,
|
|
83
|
+
0
|
|
84
|
+
]);
|
|
85
|
+
});
|
|
86
|
+
globalThis.test("never discards more than one cycle's worth", () => {
|
|
87
|
+
globalThis.expect([
|
|
88
|
+
3,
|
|
89
|
+
7,
|
|
90
|
+
10,
|
|
91
|
+
26,
|
|
92
|
+
62
|
|
93
|
+
].map(size => rejected(size).length < size)).toEqual([
|
|
94
|
+
true,
|
|
95
|
+
true,
|
|
96
|
+
true,
|
|
97
|
+
true,
|
|
98
|
+
true
|
|
99
|
+
]);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
globalThis.describe("hash", () => {
|
|
104
|
+
globalThis.test("is deterministic, which is what lets a proof be compared", () => {
|
|
105
|
+
globalThis.expect(Primitive_object.equal(Secrets_Node_Backend$ReventlessCore.provider.hash("a-secret"), Secrets_Node_Backend$ReventlessCore.provider.hash("a-secret"))).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
globalThis.test("separates different inputs", () => {
|
|
108
|
+
globalThis.expect(Primitive_object.equal(Secrets_Node_Backend$ReventlessCore.provider.hash("a-secret"), Secrets_Node_Backend$ReventlessCore.provider.hash("a-secret "))).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
globalThis.test("does not contain its input", () => {
|
|
111
|
+
globalThis.expect(Stdlib_Result.getOr(Secrets_Node_Backend$ReventlessCore.provider.hash("a-secret"), "").includes("a-secret")).toBe(false);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
globalThis.describe("Capabilities.none.secrets", () => {
|
|
116
|
+
globalThis.test("refuses both operations", () => {
|
|
117
|
+
globalThis.expect([
|
|
118
|
+
Stdlib_Result.isError(Capabilities$Reventless.none.secrets.randomToken(32, "UrlSafe")),
|
|
119
|
+
Stdlib_Result.isError(Capabilities$Reventless.none.secrets.hash("x"))
|
|
120
|
+
]).toEqual([
|
|
121
|
+
true,
|
|
122
|
+
true
|
|
123
|
+
]);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
globalThis.describe("Secrets.fixed", () => {
|
|
128
|
+
let provider = Secrets$Reventless.fixed("known", input => `hashed:` + input);
|
|
129
|
+
globalThis.test("hands back the token it was built with", () => {
|
|
130
|
+
globalThis.expect(provider.randomToken(32, "UrlSafe")).toEqual({
|
|
131
|
+
TAG: "Ok",
|
|
132
|
+
_0: "known"
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
globalThis.test("hashes through the function it was given", () => {
|
|
136
|
+
globalThis.expect(provider.hash("known")).toEqual({
|
|
137
|
+
TAG: "Ok",
|
|
138
|
+
_0: "hashed:known"
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
let Secrets;
|
|
144
|
+
|
|
145
|
+
let Backend;
|
|
146
|
+
|
|
147
|
+
export {
|
|
148
|
+
Secrets,
|
|
149
|
+
Backend,
|
|
150
|
+
token,
|
|
151
|
+
}
|
|
152
|
+
/* Not a pure module */
|
|
@@ -33,7 +33,8 @@ describe("collisionsFor", () => {
|
|
|
33
33
|
store(~qualified="Ordering.productImages", ~prefix="productImages"),
|
|
34
34
|
],
|
|
35
35
|
) {
|
|
36
|
-
| [c] =>
|
|
36
|
+
| [c] =>
|
|
37
|
+
expect((c.first.qualified, c.second.qualified, c.nested))->toEqual((
|
|
37
38
|
"Catalog.productImages",
|
|
38
39
|
"Ordering.productImages",
|
|
39
40
|
false,
|
|
@@ -36,8 +36,9 @@ describe("kebabCase", () => {
|
|
|
36
36
|
|
|
37
37
|
describe("bucketResourceName", () => {
|
|
38
38
|
testSync("qualifies a task's default bucket with its plugin", () =>
|
|
39
|
-
expect(
|
|
40
|
-
|
|
39
|
+
expect(
|
|
40
|
+
Naming.bucketResourceName(~plugin=Some("Catalog"), ~task="ImportProducts", ~bucketId=None),
|
|
41
|
+
)->toBe("catalog-import-products")
|
|
41
42
|
)
|
|
42
43
|
|
|
43
44
|
testSync("appends a declared bucket id", () =>
|
|
@@ -128,54 +128,57 @@ describe("EventLogProvisioning", () => {
|
|
|
128
128
|
EventLogProvisioning.reset()
|
|
129
129
|
})
|
|
130
130
|
|
|
131
|
-
testSync(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
let
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
~
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
131
|
+
testSync(
|
|
132
|
+
"notify delivers the ambient plugin/platform inside a construct scope, None outside",
|
|
133
|
+
() => {
|
|
134
|
+
let seen: array<(option<string>, option<string>)> = []
|
|
135
|
+
module OwnerCapture: EventLogProvisioning.Backend = {
|
|
136
|
+
let onProvisioned = (
|
|
137
|
+
~logStyle as _,
|
|
138
|
+
~name as _,
|
|
139
|
+
~owner as _,
|
|
140
|
+
~plugin,
|
|
141
|
+
~platform,
|
|
142
|
+
~resources as _,
|
|
143
|
+
~opts as _,
|
|
144
|
+
) => seen->Array.push((plugin, platform))
|
|
145
|
+
}
|
|
146
|
+
EventLogProvisioning.use(module(OwnerCapture: EventLogProvisioning.Backend))
|
|
147
|
+
|
|
148
|
+
// Outside any plugin construct: both None.
|
|
149
|
+
EventLogProvisioning.notify(
|
|
150
|
+
~logStyle=Classic,
|
|
151
|
+
~name="ProductEventLog",
|
|
152
|
+
~owner=Some(classicOwner),
|
|
153
|
+
~resources=[],
|
|
154
|
+
~opts=noOpts,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
// Inside a construct scope (what Plugin_Builder.construct establishes): both delivered.
|
|
158
|
+
let prev = ResourceAttribution.enter(~platform="online-shop", ~plugin="Catalog")
|
|
159
|
+
EventLogProvisioning.notify(
|
|
160
|
+
~logStyle=Dcb,
|
|
161
|
+
~name="CatalogDcbEventLog",
|
|
162
|
+
~owner=Some(dcbOwner),
|
|
163
|
+
~resources=[],
|
|
164
|
+
~opts=noOpts,
|
|
165
|
+
)
|
|
166
|
+
ResourceAttribution.restore(prev)
|
|
167
|
+
|
|
168
|
+
// After restore: back to None.
|
|
169
|
+
EventLogProvisioning.notify(
|
|
170
|
+
~logStyle=Classic,
|
|
171
|
+
~name="OrderEventLog",
|
|
172
|
+
~owner=None,
|
|
173
|
+
~resources=[],
|
|
174
|
+
~opts=noOpts,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
expect(seen)->toEqual([(None, None), (Some("Catalog"), Some("online-shop")), (None, None)])
|
|
178
|
+
|
|
179
|
+
EventLogProvisioning.reset()
|
|
180
|
+
},
|
|
181
|
+
)
|
|
179
182
|
|
|
180
183
|
testSync("use is single-slot: a second registration throws rather than silently winning", () => {
|
|
181
184
|
module First: EventLogProvisioning.Backend = {
|
|
@@ -19,8 +19,14 @@ describe("Monitoring", () => {
|
|
|
19
19
|
testSync("an announcement made before any backend is registered reaches the first one", () => {
|
|
20
20
|
let recorded: array<(Monitoring.unitKind, string, option<string>)> = []
|
|
21
21
|
module Late: Monitoring.Backend = {
|
|
22
|
-
let onProvisioned = (
|
|
23
|
-
|
|
22
|
+
let onProvisioned = (
|
|
23
|
+
~kind,
|
|
24
|
+
~name,
|
|
25
|
+
~component as _,
|
|
26
|
+
~plugin,
|
|
27
|
+
~platform as _,
|
|
28
|
+
~logLocator as _,
|
|
29
|
+
) => recorded->Array.push((kind, name, plugin))
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
// Provisioned at import time, inside a construct scope that is long gone by the time
|
|
@@ -42,8 +48,14 @@ describe("Monitoring", () => {
|
|
|
42
48
|
// Drained: a second registration does not receive them again.
|
|
43
49
|
let second: array<string> = []
|
|
44
50
|
module Other: Monitoring.Backend = {
|
|
45
|
-
let onProvisioned = (
|
|
46
|
-
|
|
51
|
+
let onProvisioned = (
|
|
52
|
+
~kind as _,
|
|
53
|
+
~name,
|
|
54
|
+
~component as _,
|
|
55
|
+
~plugin as _,
|
|
56
|
+
~platform as _,
|
|
57
|
+
~logLocator as _,
|
|
58
|
+
) => second->Array.push(name)
|
|
47
59
|
}
|
|
48
60
|
Monitoring.use(module(Other: Monitoring.Backend))
|
|
49
61
|
expect(second)->toEqual([])
|
|
@@ -54,12 +66,22 @@ describe("Monitoring", () => {
|
|
|
54
66
|
testSync("use registers a backend that receives every notify, role and name", () => {
|
|
55
67
|
let recorded: array<(Monitoring.unitKind, string)> = []
|
|
56
68
|
module Recorder: Monitoring.Backend = {
|
|
57
|
-
let onProvisioned = (
|
|
58
|
-
|
|
69
|
+
let onProvisioned = (
|
|
70
|
+
~kind,
|
|
71
|
+
~name,
|
|
72
|
+
~component as _,
|
|
73
|
+
~plugin as _,
|
|
74
|
+
~platform as _,
|
|
75
|
+
~logLocator as _,
|
|
76
|
+
) => recorded->Array.push((kind, name))
|
|
59
77
|
}
|
|
60
78
|
Monitoring.use(module(Recorder: Monitoring.Backend))
|
|
61
79
|
|
|
62
|
-
Monitoring.notify(
|
|
80
|
+
Monitoring.notify(
|
|
81
|
+
~kind=CommandHandler,
|
|
82
|
+
~name="AllAggregatesCmdHandler",
|
|
83
|
+
~component=stubResource,
|
|
84
|
+
)
|
|
63
85
|
Monitoring.notify(~kind=Projection, ~name="AllStateViewSlices", ~component=stubResource)
|
|
64
86
|
Monitoring.notify(~kind=DeadLetterSink, ~name="DeadLetterQueue", ~component=stubResource)
|
|
65
87
|
Monitoring.notify(~kind=Other("Counter"), ~name="ProductCounter", ~component=stubResource)
|
|
@@ -78,8 +100,14 @@ describe("Monitoring", () => {
|
|
|
78
100
|
testSync("notify forwards the static name and component resource to the backend", () => {
|
|
79
101
|
let seen: ref<option<(string, ReventlessInfra.Adapter.resource)>> = ref(None)
|
|
80
102
|
module Capture: Monitoring.Backend = {
|
|
81
|
-
let onProvisioned = (
|
|
82
|
-
|
|
103
|
+
let onProvisioned = (
|
|
104
|
+
~kind as _,
|
|
105
|
+
~name,
|
|
106
|
+
~component,
|
|
107
|
+
~plugin as _,
|
|
108
|
+
~platform as _,
|
|
109
|
+
~logLocator as _,
|
|
110
|
+
) => seen := Some((name, component))
|
|
83
111
|
}
|
|
84
112
|
Monitoring.use(module(Capture: Monitoring.Backend))
|
|
85
113
|
|
|
@@ -92,33 +120,42 @@ describe("Monitoring", () => {
|
|
|
92
120
|
Monitoring.reset()
|
|
93
121
|
})
|
|
94
122
|
|
|
95
|
-
testSync(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
let
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
(
|
|
116
|
-
(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
testSync(
|
|
124
|
+
"notify delivers the ambient plugin/platform inside a construct scope, None outside",
|
|
125
|
+
() => {
|
|
126
|
+
let seen: array<(option<string>, option<string>)> = []
|
|
127
|
+
module OwnerCapture: Monitoring.Backend = {
|
|
128
|
+
let onProvisioned = (
|
|
129
|
+
~kind as _,
|
|
130
|
+
~name as _,
|
|
131
|
+
~component as _,
|
|
132
|
+
~plugin,
|
|
133
|
+
~platform,
|
|
134
|
+
~logLocator as _,
|
|
135
|
+
) => seen->Array.push((plugin, platform))
|
|
136
|
+
}
|
|
137
|
+
Monitoring.use(module(OwnerCapture: Monitoring.Backend))
|
|
138
|
+
|
|
139
|
+
// Outside any plugin construct: platform substrate → both None.
|
|
140
|
+
Monitoring.notify(~kind=CommandHandler, ~name="ApiRouter", ~component=stubResource)
|
|
141
|
+
|
|
142
|
+
// Inside a construct scope (what Plugin_Builder.construct establishes): both delivered.
|
|
143
|
+
let prev = ResourceAttribution.enter(~platform="online-shop", ~plugin="Ordering")
|
|
144
|
+
Monitoring.notify(
|
|
145
|
+
~kind=CommandHandler,
|
|
146
|
+
~name="AllAggregatesCmdHandler",
|
|
147
|
+
~component=stubResource,
|
|
148
|
+
)
|
|
149
|
+
ResourceAttribution.restore(prev)
|
|
150
|
+
|
|
151
|
+
// After restore: back to None.
|
|
152
|
+
Monitoring.notify(~kind=Projection, ~name="AllStateViewSlices", ~component=stubResource)
|
|
153
|
+
|
|
154
|
+
expect(seen)->toEqual([(None, None), (Some("Ordering"), Some("online-shop")), (None, None)])
|
|
155
|
+
|
|
156
|
+
Monitoring.reset()
|
|
157
|
+
},
|
|
158
|
+
)
|
|
122
159
|
|
|
123
160
|
// Unlike the owner, the locator is not ambient — the seam only forwards what the provisioning
|
|
124
161
|
// site passed. A site with nothing to say omits it, and the backend must see that as "this unit
|
|
@@ -129,8 +166,14 @@ describe("Monitoring", () => {
|
|
|
129
166
|
let stubLocator: Pulumi.Output.t<string> = %raw(`{}`)
|
|
130
167
|
let seen: array<bool> = []
|
|
131
168
|
module LocatorCapture: Monitoring.Backend = {
|
|
132
|
-
let onProvisioned = (
|
|
133
|
-
|
|
169
|
+
let onProvisioned = (
|
|
170
|
+
~kind as _,
|
|
171
|
+
~name as _,
|
|
172
|
+
~component as _,
|
|
173
|
+
~plugin as _,
|
|
174
|
+
~platform as _,
|
|
175
|
+
~logLocator,
|
|
176
|
+
) => seen->Array.push(logLocator->Option.isSome)
|
|
134
177
|
}
|
|
135
178
|
Monitoring.use(module(LocatorCapture: Monitoring.Backend))
|
|
136
179
|
|
|
@@ -46,8 +46,8 @@ describe("QueryInterception", () => {
|
|
|
46
46
|
|
|
47
47
|
testSync("and registering a runtime interceptor does not switch provisioning on", () => {
|
|
48
48
|
Interception.reset()
|
|
49
|
-
QueryDb_Callback.registerQueryInterceptor(
|
|
50
|
-
Promise.resolve(QueryDb_Callback.Allow)
|
|
49
|
+
QueryDb_Callback.registerQueryInterceptor(
|
|
50
|
+
(~identity as _, ~readModelName as _, ~args as _) => Promise.resolve(QueryDb_Callback.Allow),
|
|
51
51
|
)
|
|
52
52
|
expect(Interception.isEnabled())->toBe(false)
|
|
53
53
|
QueryDb_Callback.clearQueryInterceptor()
|
|
@@ -17,39 +17,47 @@ describe("Auth_RefusalVocabulary — the table", () => {
|
|
|
17
17
|
})
|
|
18
18
|
|
|
19
19
|
testSync("each adapter can express both refusals", () => {
|
|
20
|
-
[Local, AppSync]->Array.forEach(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
[Local, AppSync]->Array.forEach(
|
|
21
|
+
adapter => {
|
|
22
|
+
let kinds = signalsFor(adapter)->Array.map(s => s.kind)
|
|
23
|
+
expect(kinds->Array.includes(Entitlement))->toBe(true)
|
|
24
|
+
expect(kinds->Array.includes(Identity))->toBe(true)
|
|
25
|
+
},
|
|
26
|
+
)
|
|
25
27
|
})
|
|
26
28
|
|
|
27
29
|
testSync("within an adapter the two refusals are actually distinguishable", () => {
|
|
28
30
|
// A mapping whose two rows look identical to a client would be worthless —
|
|
29
31
|
// it has to differ in the status, the place to look, or the value found.
|
|
30
|
-
[Local, AppSync]->Array.forEach(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
[Local, AppSync]->Array.forEach(
|
|
33
|
+
adapter => {
|
|
34
|
+
let signals = signalsFor(adapter)
|
|
35
|
+
let entitlement = signals->Array.find(s => s.kind == Entitlement)
|
|
36
|
+
let identity = signals->Array.find(s => s.kind == Identity)
|
|
37
|
+
switch (entitlement, identity) {
|
|
38
|
+
| (Some(e), Some(i)) =>
|
|
39
|
+
let differs =
|
|
40
|
+
e.httpStatus != i.httpStatus || e.discriminator != i.discriminator || e.value != i.value
|
|
41
|
+
expect(differs)->toBe(true)
|
|
42
|
+
| _ => JsError.throwWithMessage("adapter is missing one of the two refusals")
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
)
|
|
42
46
|
})
|
|
43
47
|
})
|
|
44
48
|
|
|
45
49
|
describe("Auth_RefusalVocabulary.classify", () => {
|
|
46
50
|
testSync("classifies every row of the table as that row's kind", () => {
|
|
47
|
-
signals->Array.forEach(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
signals->Array.forEach(
|
|
52
|
+
s => {
|
|
53
|
+
let errorType = s.discriminator->String.includes("errorType") ? Some(s.value) : None
|
|
54
|
+
let extensionsCode = s.discriminator == "extensions.code" ? Some(s.value) : None
|
|
55
|
+
// The 401 row's discriminator is a response header; status alone carries it.
|
|
56
|
+
expect(classify(~httpStatus=s.httpStatus, ~errorType?, ~extensionsCode?))->toEqual(
|
|
57
|
+
Some(s.kind),
|
|
58
|
+
)
|
|
59
|
+
},
|
|
60
|
+
)
|
|
53
61
|
})
|
|
54
62
|
|
|
55
63
|
// The trap the table exists to defuse: on AppSync the entitlement value is a
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
open JestGlobals
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
// The point of the seam, end to end at the hook level: an extension that only
|
|
5
4
|
// ever gets `onColdStart` can reach the framework's runtime callback hooks from
|
|
6
5
|
// there, and they take effect on the requests that follow.
|
|
@@ -49,13 +48,15 @@ describe("RuntimeExtension reaches the runtime callback hooks", () => {
|
|
|
49
48
|
let companionModuleUrls = []
|
|
50
49
|
let onColdStart = (~runtimeKind as _, ~component, ~plugin as _, ~platform as _) => {
|
|
51
50
|
seenAtColdStart->Array.push(component)
|
|
52
|
-
CommandGenerator_Callback.registerCommandInterceptor(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
CommandGenerator_Callback.registerCommandInterceptor(
|
|
52
|
+
async (
|
|
53
|
+
~identity as _,
|
|
54
|
+
~componentName,
|
|
55
|
+
~componentKind as _,
|
|
56
|
+
~tag,
|
|
57
|
+
~args as _,
|
|
58
|
+
) => CommandGenerator_Callback.Deny(`${componentName}.${tag} refused`),
|
|
59
|
+
)
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
RuntimeExtension.use(module(Gatekeeper: RuntimeExtension.Extension))
|
|
@@ -7,9 +7,11 @@ type call = {
|
|
|
7
7
|
platform: option<string>,
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
let recorderNamed = (
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
let recorderNamed = (
|
|
11
|
+
~companions: array<string>=[],
|
|
12
|
+
label: string,
|
|
13
|
+
into: array<(string, call)>,
|
|
14
|
+
): module(RuntimeExtension.Extension) => {
|
|
13
15
|
module R = {
|
|
14
16
|
let moduleUrl = `file:///pkg/${label}.res.mjs`
|
|
15
17
|
let companionModuleUrls = companions
|
|
@@ -442,25 +442,32 @@ guards->Array.forEach(g => {
|
|
|
442
442
|
describe(g.gqlType, () => {
|
|
443
443
|
// Without this, a renamed GraphQL type or an unreadable schema would make
|
|
444
444
|
// every assertion below pass over two empty lists.
|
|
445
|
-
testSync(
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
445
|
+
testSync(
|
|
446
|
+
"the SDL block and the record schema are both readable",
|
|
447
|
+
() => {
|
|
448
|
+
expect(sdlFields->Array.length > 0)->toEqual(true)
|
|
449
|
+
expect(g.recordFields->Array.length > 0)->toEqual(true)
|
|
450
|
+
},
|
|
451
|
+
)
|
|
449
452
|
|
|
450
|
-
testSync(
|
|
451
|
-
|
|
453
|
+
testSync(
|
|
454
|
+
"every encoded field is selectable",
|
|
455
|
+
() => expect(missing(g.wireFields, sdlFields))->toEqual([]),
|
|
452
456
|
)
|
|
453
457
|
|
|
454
|
-
testSync(
|
|
455
|
-
|
|
458
|
+
testSync(
|
|
459
|
+
"every declared field is encoded",
|
|
460
|
+
() => expect(missing(sdlFields, g.wireFields))->toEqual([]),
|
|
456
461
|
)
|
|
457
462
|
|
|
458
|
-
testSync(
|
|
459
|
-
|
|
463
|
+
testSync(
|
|
464
|
+
"every record field reaches the wire",
|
|
465
|
+
() => expect(missing(g.recordFields, Array.concat(sdlFields, g.recordOnly)))->toEqual([]),
|
|
460
466
|
)
|
|
461
467
|
|
|
462
|
-
testSync(
|
|
463
|
-
|
|
468
|
+
testSync(
|
|
469
|
+
"the wire carries nothing the record and the divergences do not name",
|
|
470
|
+
() => expect(missing(sdlFields, Array.concat(g.recordFields, g.wireOnly)))->toEqual([]),
|
|
464
471
|
)
|
|
465
472
|
})
|
|
466
473
|
})
|
|
@@ -479,10 +486,9 @@ describe("derivedPages", () => {
|
|
|
479
486
|
)
|
|
480
487
|
expect(jsonKeys(baked)->Array.includes("derivedPages"))->toEqual(true)
|
|
481
488
|
expect(
|
|
482
|
-
sdlFieldNames(
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
)->Array.includes("derivedPages"),
|
|
489
|
+
sdlFieldNames(~typeName="Platform_ComponentDefinitionEntry", componentSdl)->Array.includes(
|
|
490
|
+
"derivedPages",
|
|
491
|
+
),
|
|
486
492
|
)->toEqual(false)
|
|
487
493
|
})
|
|
488
494
|
})
|