@reventlessdev/reventless-local 3.0.0-alpha.197 → 3.0.0-alpha.199
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 +17 -0
- package/package.json +9 -9
- package/src/Platform.res +3 -0
- package/src/Platform.res.mjs +3 -0
- package/src/adapter/LocalCapabilities.res +13 -0
- package/src/adapter/LocalCapabilities.res.mjs +12 -0
- package/src/adapter/LocalGeocodeResolvers.res +63 -0
- package/src/adapter/LocalGeocodeResolvers.res.mjs +58 -0
- package/src/components/OutboundTranslationSlice_Builder.res +1 -0
- package/src/components/OutboundTranslationSlice_Builder.res.mjs +2 -1
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res +26 -10
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res.mjs +30 -10
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res +5 -2
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res.mjs +2 -2
- package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res +1 -1
- package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
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.199 (2026-08-04)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **geocoding:** serve geocoding through the platform GraphQL API (D9 half 2) ([914d3c0](https://github.com/ReventlessDev/reventless-core/commit/914d3c0a99a1b67ffb89e2b8259dd30f67ff9bae))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# 3.0.0-alpha.198 (2026-08-04)
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **core:** tag a slice's published command with its target, not itself ([bb2b063](https://github.com/ReventlessDev/reventless-core/commit/bb2b063f914e45fb8efcba28e0b691713cf93d8a))
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* **outbound:** hand translate its geocoder instead of making it fetch one ([fb18312](https://github.com/ReventlessDev/reventless-core/commit/fb1831216b37c9562868c46e1a09054e69418c67))
|
|
21
|
+
|
|
22
|
+
|
|
6
23
|
# 3.0.0-alpha.197 (2026-08-03)
|
|
7
24
|
|
|
8
25
|
**Note:** Version bump only for package @reventlessdev/reventless-local
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-local",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.199",
|
|
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": {
|
|
@@ -35,17 +35,17 @@
|
|
|
35
35
|
"sury": "11.0.0-alpha.4",
|
|
36
36
|
"ws": "^8.18.0",
|
|
37
37
|
"@reventlessdev/rescript-effect": "0.1.0-alpha.32",
|
|
38
|
-
"@reventlessdev/rescript-
|
|
38
|
+
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
39
39
|
"@reventlessdev/rescript-node": "2.0.0-alpha.1",
|
|
40
|
+
"@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.26",
|
|
40
41
|
"@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.21",
|
|
41
|
-
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
42
42
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.18",
|
|
43
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.
|
|
44
|
-
"@reventlessdev/reventless-graphql-server": "1.0.0-alpha.
|
|
45
|
-
"@reventlessdev/reventless-
|
|
46
|
-
"@reventlessdev/reventless-
|
|
47
|
-
"@reventlessdev/reventless-
|
|
48
|
-
"@reventlessdev/reventless-
|
|
43
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.211",
|
|
44
|
+
"@reventlessdev/reventless-graphql-server": "1.0.0-alpha.59",
|
|
45
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.126",
|
|
46
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.75",
|
|
47
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.100",
|
|
48
|
+
"@reventlessdev/reventless-gwt": "1.0.0-alpha.158"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"rescript": "12.3.0",
|
package/src/Platform.res
CHANGED
|
@@ -1938,6 +1938,9 @@ module MakeWithConfig = (
|
|
|
1938
1938
|
// Upload service (route B) on the domain server — mirrors adding it to
|
|
1939
1939
|
// `domainBaseFragment` on AWS.
|
|
1940
1940
|
LocalUploadResolvers.register(DomainGraphQL_Server.asInterface)
|
|
1941
|
+
// Geocoding client door (D9 half 2) on the domain server — same mirror. A dev
|
|
1942
|
+
// stub (no real geocoder locally), so the map picker's search box works offline.
|
|
1943
|
+
LocalGeocodeResolvers.register(DomainGraphQL_Server.asInterface)
|
|
1941
1944
|
// In split mode, inject Relay base types (Node interface, PageInfo) into the platform
|
|
1942
1945
|
// server so SDL fragments compile. The node(id) query is Domain-only — the Platform
|
|
1943
1946
|
// API is consumed by admin tools and agents, not Relay clients.
|
package/src/Platform.res.mjs
CHANGED
|
@@ -61,6 +61,7 @@ import * as EventPublish_Callback$ReventlessCore from "@reventlessdev/reventless
|
|
|
61
61
|
import * as LocalUploadResolvers$ReventlessLocal from "./adapter/LocalUploadResolvers.res.mjs";
|
|
62
62
|
import * as ProjectionCheckpoint$ReventlessLocal from "./adapter/ProjectionCheckpoint.res.mjs";
|
|
63
63
|
import * as ExtensionPointMapping$ReventlessInfra from "@reventlessdev/reventless-infra/src/types/ExtensionPointMapping.res.mjs";
|
|
64
|
+
import * as LocalGeocodeResolvers$ReventlessLocal from "./adapter/LocalGeocodeResolvers.res.mjs";
|
|
64
65
|
import * as UiFragments_Projection$ReventlessCore from "@reventlessdev/reventless-core/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments_Projection.res.mjs";
|
|
65
66
|
import * as EventLogStorage_Sqlite$ReventlessLocal from "./adapter/EventLog/EventLogStorage_Sqlite.res.mjs";
|
|
66
67
|
import * as ExtensionPoint_Builder$ReventlessLocal from "./components/ExtensionPoint_Builder.res.mjs";
|
|
@@ -1559,6 +1560,7 @@ function MakeWithConfig(Config) {
|
|
|
1559
1560
|
DomainGraphQL_Server$ReventlessLocal.registerTypes(GraphQL_Stitcher$ReventlessCore.relayBaseTypes);
|
|
1560
1561
|
DomainGraphQL_Server$ReventlessLocal.registerQueries(GraphQL_Stitcher$ReventlessCore.relayBaseQueries, {});
|
|
1561
1562
|
LocalUploadResolvers$ReventlessLocal.register(DomainGraphQL_Server$ReventlessLocal.asInterface);
|
|
1563
|
+
LocalGeocodeResolvers$ReventlessLocal.register(DomainGraphQL_Server$ReventlessLocal.asInterface);
|
|
1562
1564
|
if (Config.splitApi) {
|
|
1563
1565
|
PlatformGraphQL_Server$ReventlessLocal.registerTypes(GraphQL_Stitcher$ReventlessCore.relayBaseTypes);
|
|
1564
1566
|
}
|
|
@@ -3244,6 +3246,7 @@ function Make($star) {
|
|
|
3244
3246
|
DomainGraphQL_Server$ReventlessLocal.registerTypes(GraphQL_Stitcher$ReventlessCore.relayBaseTypes);
|
|
3245
3247
|
DomainGraphQL_Server$ReventlessLocal.registerQueries(GraphQL_Stitcher$ReventlessCore.relayBaseQueries, {});
|
|
3246
3248
|
LocalUploadResolvers$ReventlessLocal.register(DomainGraphQL_Server$ReventlessLocal.asInterface);
|
|
3249
|
+
LocalGeocodeResolvers$ReventlessLocal.register(DomainGraphQL_Server$ReventlessLocal.asInterface);
|
|
3247
3250
|
PlatformGraphQL_Server$ReventlessLocal.registerTypes(GraphQL_Stitcher$ReventlessCore.relayBaseTypes);
|
|
3248
3251
|
currentDeployTarget.contents = "Domain";
|
|
3249
3252
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// What the local platform hands a slice's `translate`.
|
|
2
|
+
//
|
|
3
|
+
// Nothing, today — and that is the honest answer rather than a placeholder. The
|
|
4
|
+
// local platform provisions no geocoder (a deployed stack's place index is an
|
|
5
|
+
// account and a bill), so `Capabilities.none` reports `Unavailable`, which
|
|
6
|
+
// `translate` maps to a retryable `Error` and the sweep surfaces. A dev running
|
|
7
|
+
// a geocoding slice sees its items stay queued, which is true, instead of seeing
|
|
8
|
+
// them written off as unresolvable addresses, which would not be.
|
|
9
|
+
//
|
|
10
|
+
// This is the one place to change when local grows a real one — a fixture, a
|
|
11
|
+
// stub keyed by address, or Nominatim. Slices reach it through the injected
|
|
12
|
+
// record, so nothing in a plugin moves on that day.
|
|
13
|
+
let capabilities = () => Reventless.Capabilities.none
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Capabilities$Reventless from "@reventlessdev/reventless-spec/src/semantic/Capabilities.res.mjs";
|
|
4
|
+
|
|
5
|
+
function capabilities() {
|
|
6
|
+
return Capabilities$Reventless.none;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
capabilities,
|
|
11
|
+
}
|
|
12
|
+
/* No side effect */
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Local geocode resolver — the *client* door of the geocoding capability (D9 half
|
|
2
|
+
// 2) on the dev platform. Registers `Query.geocode` on the domain server the same
|
|
3
|
+
// way `LocalUploadResolvers` registers `Upload_Presign`, which is the local analogue
|
|
4
|
+
// of adding the field to `domainBaseFragment` on AWS.
|
|
5
|
+
//
|
|
6
|
+
// This closes a dev-experience gap: before it, `config.geocoderEndpoint` was unset
|
|
7
|
+
// in local dev, so the map picker's search box did not render at all and the input
|
|
8
|
+
// was click-to-place only. With this door registered, address search works in dev.
|
|
9
|
+
//
|
|
10
|
+
// The dev platform provisions no real geocoder — `LocalCapabilities` keeps the
|
|
11
|
+
// *unattended* slice path at `Capabilities.none`, and the two doors are
|
|
12
|
+
// independent. This browser door is a deterministic stub: a non-empty query
|
|
13
|
+
// resolves to one candidate whose point is a stable function of the query text, so
|
|
14
|
+
// a search places a pin, in the same spot every time, with no network call or API
|
|
15
|
+
// key. The coordinates are placeholders — echoed back beside the query as the label
|
|
16
|
+
// — not a real geocode. An empty query yields no results, matching the AWS door and
|
|
17
|
+
// the browser's cleared-input case.
|
|
18
|
+
|
|
19
|
+
// A stable, in-range `(lat, lng)` derived from the query text: fold the character
|
|
20
|
+
// codes into one number and map it into safe coordinate bands. Deterministic, so a
|
|
21
|
+
// dev search is reproducible across reloads.
|
|
22
|
+
let stubPoint = (text: string): (float, float) => {
|
|
23
|
+
let sum = ref(0)
|
|
24
|
+
for i in 0 to text->String.length - 1 {
|
|
25
|
+
let code = text->String.codePointAt(i)->Option.getOr(0)
|
|
26
|
+
sum := sum.contents + code * (i + 1)
|
|
27
|
+
}
|
|
28
|
+
let n = sum.contents
|
|
29
|
+
let lat = mod(n, 120)->Int.toFloat -. 60.0 // −60 … 59
|
|
30
|
+
let lng = mod(n / 7, 240)->Int.toFloat -. 120.0 // −120 … 119
|
|
31
|
+
(lat, lng)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let register = (server: ReventlessGraphqlServer.GraphQL_ServerInstance.t): unit => {
|
|
35
|
+
let resolvers = Dict.make()
|
|
36
|
+
resolvers->Dict.set("geocode", async (_root, args, _ctx): JSON.t => {
|
|
37
|
+
let obj = args->JSON.Decode.object->Option.getOr(Dict.make())
|
|
38
|
+
let text =
|
|
39
|
+
obj
|
|
40
|
+
->Dict.get("text")
|
|
41
|
+
->Option.flatMap(JSON.Decode.string)
|
|
42
|
+
->Option.getOr("")
|
|
43
|
+
->String.trim
|
|
44
|
+
if text == "" {
|
|
45
|
+
JSON.Encode.array([])
|
|
46
|
+
} else {
|
|
47
|
+
let (lat, lng) = stubPoint(text)
|
|
48
|
+
let candidate =
|
|
49
|
+
Dict.fromArray([
|
|
50
|
+
("label", JSON.Encode.string(text)),
|
|
51
|
+
("lat", JSON.Encode.float(lat)),
|
|
52
|
+
("lng", JSON.Encode.float(lng)),
|
|
53
|
+
("relevance", JSON.Encode.float(1.0)),
|
|
54
|
+
])->JSON.Encode.object
|
|
55
|
+
JSON.Encode.array([candidate])
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
server.registerTypes(~sdlTypes=ReventlessCore.Platform_AdminApi.geocodeTypes)
|
|
59
|
+
server.registerQueries(
|
|
60
|
+
~sdlFields=ReventlessCore.Platform_AdminApi.geocodeQueryFields,
|
|
61
|
+
~resolvers,
|
|
62
|
+
)
|
|
63
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
4
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Platform_AdminApi$ReventlessCore from "@reventlessdev/reventless-core/src/admin/Platform_AdminApi.res.mjs";
|
|
6
|
+
|
|
7
|
+
function stubPoint(text) {
|
|
8
|
+
let sum = 0;
|
|
9
|
+
for (let i = 0, i_finish = text.length; i < i_finish; ++i) {
|
|
10
|
+
let code = Stdlib_Option.getOr(text.codePointAt(i), 0);
|
|
11
|
+
sum = sum + (code * (i + 1 | 0) | 0) | 0;
|
|
12
|
+
}
|
|
13
|
+
let n = sum;
|
|
14
|
+
let lat = n % 120 - 60.0;
|
|
15
|
+
let lng = (n / 7 | 0) % 240 - 120.0;
|
|
16
|
+
return [
|
|
17
|
+
lat,
|
|
18
|
+
lng
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function register(server) {
|
|
23
|
+
let resolvers = {};
|
|
24
|
+
resolvers["geocode"] = async (_root, args, _ctx) => {
|
|
25
|
+
let obj = Stdlib_Option.getOr(Stdlib_JSON.Decode.object(args), {});
|
|
26
|
+
let text = Stdlib_Option.getOr(Stdlib_Option.flatMap(obj["text"], Stdlib_JSON.Decode.string), "").trim();
|
|
27
|
+
if (text === "") {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
let match = stubPoint(text);
|
|
31
|
+
return [Object.fromEntries([
|
|
32
|
+
[
|
|
33
|
+
"label",
|
|
34
|
+
text
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
"lat",
|
|
38
|
+
match[0]
|
|
39
|
+
],
|
|
40
|
+
[
|
|
41
|
+
"lng",
|
|
42
|
+
match[1]
|
|
43
|
+
],
|
|
44
|
+
[
|
|
45
|
+
"relevance",
|
|
46
|
+
1.0
|
|
47
|
+
]
|
|
48
|
+
])];
|
|
49
|
+
};
|
|
50
|
+
server.registerTypes(Platform_AdminApi$ReventlessCore.geocodeTypes);
|
|
51
|
+
server.registerQueries(Platform_AdminApi$ReventlessCore.geocodeQueryFields, resolvers);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export {
|
|
55
|
+
stubPoint,
|
|
56
|
+
register,
|
|
57
|
+
}
|
|
58
|
+
/* Platform_AdminApi-ReventlessCore Not a pure module */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Component$ReventlessCore from "@reventlessdev/reventless-core/src/components/Component.res.mjs";
|
|
4
|
+
import * as LocalCapabilities$ReventlessLocal from "../adapter/LocalCapabilities.res.mjs";
|
|
4
5
|
import * as LocalQueryDbStorage$ReventlessLocal from "../adapter/QueryDb/LocalQueryDbStorage.res.mjs";
|
|
5
6
|
import * as LocalRuntimeEnvironment$ReventlessLocal from "../adapter/Runtime/LocalRuntimeEnvironment.res.mjs";
|
|
6
7
|
import * as QueryDbResolvers_GraphQL$ReventlessLocal from "../adapter/QueryDb/QueryDbResolvers_GraphQL.res.mjs";
|
|
@@ -32,7 +33,7 @@ function Make(Bus) {
|
|
|
32
33
|
make: QueryDbStorage.make
|
|
33
34
|
})({
|
|
34
35
|
make: QueryDbResolvers.make
|
|
35
|
-
})(EventCollectorChannel)(EventCollectorRuntimeBuilder)(Api);
|
|
36
|
+
})(EventCollectorChannel)(EventCollectorRuntimeBuilder)(Api)(LocalCapabilities$ReventlessLocal);
|
|
36
37
|
let Make$1 = Spec => (Translation => {
|
|
37
38
|
let Inner = CoreMaker.Make(Spec)(Translation);
|
|
38
39
|
return {
|
|
@@ -70,7 +70,7 @@ describe("OutboundTranslationSlice Callback", () => {
|
|
|
70
70
|
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
71
71
|
publishedCommands := cmds
|
|
72
72
|
}
|
|
73
|
-
await FireForgetCallback.phase2(mockPublish)
|
|
73
|
+
await FireForgetCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
|
|
74
74
|
expect(publishedCommands.contents->Array.length)->toBe(0)
|
|
75
75
|
let row = FireForgetCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
76
76
|
expect(row.status)->toBe(Completed)
|
|
@@ -81,7 +81,7 @@ describe("OutboundTranslationSlice Callback", () => {
|
|
|
81
81
|
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
82
82
|
publishedCommands := cmds
|
|
83
83
|
}
|
|
84
|
-
await FireForgetCallback.phase2(mockPublish)
|
|
84
|
+
await FireForgetCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
|
|
85
85
|
expect(publishedCommands.contents->Array.length)->toBe(0)
|
|
86
86
|
})
|
|
87
87
|
})
|
|
@@ -93,7 +93,7 @@ describe("OutboundTranslationSlice Callback", () => {
|
|
|
93
93
|
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
94
94
|
publishedCommands := Array.concat(publishedCommands.contents, cmds)
|
|
95
95
|
}
|
|
96
|
-
await CommandBackCallback.phase2(mockPublish)
|
|
96
|
+
await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
|
|
97
97
|
expect(publishedCommands.contents->Array.length)->toBe(1)
|
|
98
98
|
let cmd = publishedCommands.contents->Array.getUnsafe(0)
|
|
99
99
|
expect(cmd.id)->toBe("ord-1")
|
|
@@ -101,12 +101,28 @@ describe("OutboundTranslationSlice Callback", () => {
|
|
|
101
101
|
expect(row.status)->toBe(Completed)
|
|
102
102
|
})
|
|
103
103
|
|
|
104
|
+
// The published command's `meta.service` must name the TARGET, not this
|
|
105
|
+
// slice. An aggregate derives its event's meta from the command's, and
|
|
106
|
+
// ReadModel/AutomationSlice callbacks dispatch mappings on `meta.service` —
|
|
107
|
+
// so a slice that stamps its own name here makes the target's events match
|
|
108
|
+
// no mapping and project as zero actions, with no error anywhere.
|
|
109
|
+
testPromise("published command is tagged with the target's name", async () => {
|
|
110
|
+
CommandBackCallback.phase1([("evt", PaymentReceived({orderId: "ord-1", amount: 50.0}))])
|
|
111
|
+
let publishedCommands = ref([])
|
|
112
|
+
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
113
|
+
publishedCommands := Array.concat(publishedCommands.contents, cmds)
|
|
114
|
+
}
|
|
115
|
+
await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
|
|
116
|
+
let cmd = publishedCommands.contents->Array.getUnsafe(0)
|
|
117
|
+
expect(cmd.meta.service)->toBe("ConfirmPayment")
|
|
118
|
+
})
|
|
119
|
+
|
|
104
120
|
testPromise("Error marks item as Failed with incremented retryCount", async () => {
|
|
105
121
|
ProcessPaymentSpec.translateFn := (async (_id, _item) => Error("gateway timeout"))
|
|
106
122
|
|
|
107
123
|
CommandBackCallback.phase1([("evt", PaymentReceived({orderId: "ord-1", amount: 50.0}))])
|
|
108
124
|
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => ()
|
|
109
|
-
await CommandBackCallback.phase2(mockPublish)
|
|
125
|
+
await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
|
|
110
126
|
|
|
111
127
|
let row = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
112
128
|
expect(row.status)->toBe(Failed)
|
|
@@ -118,7 +134,7 @@ describe("OutboundTranslationSlice Callback", () => {
|
|
|
118
134
|
ProcessPaymentSpec.translateFn := (async (_id, _item) => Error("timeout"))
|
|
119
135
|
CommandBackCallback.phase1([("evt", PaymentReceived({orderId: "ord-1", amount: 50.0}))])
|
|
120
136
|
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => ()
|
|
121
|
-
await CommandBackCallback.phase2(mockPublish)
|
|
137
|
+
await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
|
|
122
138
|
let row1 = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
123
139
|
expect(row1.retryCount)->toBe(1)
|
|
124
140
|
|
|
@@ -129,7 +145,7 @@ describe("OutboundTranslationSlice Callback", () => {
|
|
|
129
145
|
let successPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
130
146
|
publishedCommands := cmds
|
|
131
147
|
}
|
|
132
|
-
await CommandBackCallback.phase2(successPublish)
|
|
148
|
+
await CommandBackCallback.phase2(successPublish, ~capabilities=Reventless.Capabilities.none)
|
|
133
149
|
expect(publishedCommands.contents->Array.length)->toBe(1)
|
|
134
150
|
let row2 = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
135
151
|
expect(row2.status)->toBe(Completed)
|
|
@@ -142,8 +158,8 @@ describe("OutboundTranslationSlice Callback", () => {
|
|
|
142
158
|
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => ()
|
|
143
159
|
|
|
144
160
|
// Fail twice
|
|
145
|
-
await CommandBackCallback.phase2(mockPublish)
|
|
146
|
-
await CommandBackCallback.phase2(mockPublish)
|
|
161
|
+
await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
|
|
162
|
+
await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
|
|
147
163
|
let row = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
148
164
|
expect(row.retryCount)->toBe(2)
|
|
149
165
|
|
|
@@ -152,7 +168,7 @@ describe("OutboundTranslationSlice Callback", () => {
|
|
|
152
168
|
let trackPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
153
169
|
publishedCommands := cmds
|
|
154
170
|
}
|
|
155
|
-
await CommandBackCallback.phase2(trackPublish)
|
|
171
|
+
await CommandBackCallback.phase2(trackPublish, ~capabilities=Reventless.Capabilities.none)
|
|
156
172
|
expect(publishedCommands.contents->Array.length)->toBe(0)
|
|
157
173
|
let row2 = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
|
158
174
|
// retryCount should still be 2 — not retried
|
|
@@ -178,7 +194,7 @@ describe("OutboundTranslationSlice Callback", () => {
|
|
|
178
194
|
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async cmds => {
|
|
179
195
|
publishedCommands := Array.concat(publishedCommands.contents, cmds)
|
|
180
196
|
}
|
|
181
|
-
await CommandBackCallback.phase2(mockPublish)
|
|
197
|
+
await CommandBackCallback.phase2(mockPublish, ~capabilities=Reventless.Capabilities.none)
|
|
182
198
|
|
|
183
199
|
// ord-1 should be Failed, ord-2 should be Completed
|
|
184
200
|
let row1 = CommandBackCallback.todoItems->Dict.get("ord-1")->Option.getOrThrow
|
package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
4
4
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Capabilities$Reventless from "@reventlessdev/reventless-spec/src/semantic/Capabilities.res.mjs";
|
|
5
6
|
import * as OutboundTranslationSliceFixtures$ReventlessLocal from "./OutboundTranslationSliceFixtures.res.mjs";
|
|
6
7
|
import * as OutboundTranslationSlice_Callback$ReventlessCore from "@reventlessdev/reventless-core/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs";
|
|
7
8
|
|
|
@@ -145,7 +146,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
|
|
|
145
146
|
let mockPublish = async cmds => {
|
|
146
147
|
publishedCommands.contents = cmds;
|
|
147
148
|
};
|
|
148
|
-
await FireForgetCallback.phase2(mockPublish);
|
|
149
|
+
await FireForgetCallback.phase2(mockPublish, Capabilities$Reventless.none);
|
|
149
150
|
globalThis.expect(publishedCommands.contents.length).toBe(0);
|
|
150
151
|
let row = Stdlib_Option.getOrThrow(FireForgetCallback.todoItems["ord-1"], undefined);
|
|
151
152
|
globalThis.expect(row.status).toBe("Completed");
|
|
@@ -157,7 +158,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
|
|
|
157
158
|
let mockPublish = async cmds => {
|
|
158
159
|
publishedCommands.contents = cmds;
|
|
159
160
|
};
|
|
160
|
-
await FireForgetCallback.phase2(mockPublish);
|
|
161
|
+
await FireForgetCallback.phase2(mockPublish, Capabilities$Reventless.none);
|
|
161
162
|
globalThis.expect(publishedCommands.contents.length).toBe(0);
|
|
162
163
|
});
|
|
163
164
|
});
|
|
@@ -177,13 +178,32 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
|
|
|
177
178
|
let mockPublish = async cmds => {
|
|
178
179
|
publishedCommands.contents = publishedCommands.contents.concat(cmds);
|
|
179
180
|
};
|
|
180
|
-
await CommandBackCallback.phase2(mockPublish);
|
|
181
|
+
await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
|
|
181
182
|
globalThis.expect(publishedCommands.contents.length).toBe(1);
|
|
182
183
|
let cmd = publishedCommands.contents[0];
|
|
183
184
|
globalThis.expect(cmd.id).toBe("ord-1");
|
|
184
185
|
let row = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
|
|
185
186
|
globalThis.expect(row.status).toBe("Completed");
|
|
186
187
|
});
|
|
188
|
+
globalThis.test("published command is tagged with the target's name", async () => {
|
|
189
|
+
CommandBackCallback.phase1([[
|
|
190
|
+
"evt",
|
|
191
|
+
{
|
|
192
|
+
TAG: "PaymentReceived",
|
|
193
|
+
orderId: "ord-1",
|
|
194
|
+
amount: 50.0
|
|
195
|
+
}
|
|
196
|
+
]]);
|
|
197
|
+
let publishedCommands = {
|
|
198
|
+
contents: []
|
|
199
|
+
};
|
|
200
|
+
let mockPublish = async cmds => {
|
|
201
|
+
publishedCommands.contents = publishedCommands.contents.concat(cmds);
|
|
202
|
+
};
|
|
203
|
+
await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
|
|
204
|
+
let cmd = publishedCommands.contents[0];
|
|
205
|
+
globalThis.expect(cmd.meta.service).toBe("ConfirmPayment");
|
|
206
|
+
});
|
|
187
207
|
globalThis.test("Error marks item as Failed with incremented retryCount", async () => {
|
|
188
208
|
OutboundTranslationSliceFixtures$ReventlessLocal.ProcessPaymentSpec.translateFn.contents = async (_id, _item) => ({
|
|
189
209
|
TAG: "Error",
|
|
@@ -198,7 +218,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
|
|
|
198
218
|
}
|
|
199
219
|
]]);
|
|
200
220
|
let mockPublish = async _cmds => {};
|
|
201
|
-
await CommandBackCallback.phase2(mockPublish);
|
|
221
|
+
await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
|
|
202
222
|
let row = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
|
|
203
223
|
globalThis.expect(row.status).toBe("Failed");
|
|
204
224
|
globalThis.expect(row.retryCount).toBe(1);
|
|
@@ -217,7 +237,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
|
|
|
217
237
|
}
|
|
218
238
|
]]);
|
|
219
239
|
let mockPublish = async _cmds => {};
|
|
220
|
-
await CommandBackCallback.phase2(mockPublish);
|
|
240
|
+
await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
|
|
221
241
|
let row1 = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
|
|
222
242
|
globalThis.expect(row1.retryCount).toBe(1);
|
|
223
243
|
OutboundTranslationSliceFixtures$ReventlessLocal.ProcessPaymentSpec.translateFn.contents = async (id, _item) => ({
|
|
@@ -236,7 +256,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
|
|
|
236
256
|
let successPublish = async cmds => {
|
|
237
257
|
publishedCommands.contents = cmds;
|
|
238
258
|
};
|
|
239
|
-
await CommandBackCallback.phase2(successPublish);
|
|
259
|
+
await CommandBackCallback.phase2(successPublish, Capabilities$Reventless.none);
|
|
240
260
|
globalThis.expect(publishedCommands.contents.length).toBe(1);
|
|
241
261
|
let row2 = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
|
|
242
262
|
globalThis.expect(row2.status).toBe("Completed");
|
|
@@ -255,8 +275,8 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
|
|
|
255
275
|
}
|
|
256
276
|
]]);
|
|
257
277
|
let mockPublish = async _cmds => {};
|
|
258
|
-
await CommandBackCallback.phase2(mockPublish);
|
|
259
|
-
await CommandBackCallback.phase2(mockPublish);
|
|
278
|
+
await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
|
|
279
|
+
await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
|
|
260
280
|
let row = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
|
|
261
281
|
globalThis.expect(row.retryCount).toBe(2);
|
|
262
282
|
let publishedCommands = {
|
|
@@ -265,7 +285,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
|
|
|
265
285
|
let trackPublish = async cmds => {
|
|
266
286
|
publishedCommands.contents = cmds;
|
|
267
287
|
};
|
|
268
|
-
await CommandBackCallback.phase2(trackPublish);
|
|
288
|
+
await CommandBackCallback.phase2(trackPublish, Capabilities$Reventless.none);
|
|
269
289
|
globalThis.expect(publishedCommands.contents.length).toBe(0);
|
|
270
290
|
let row2 = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
|
|
271
291
|
globalThis.expect(row2.retryCount).toBe(2);
|
|
@@ -318,7 +338,7 @@ globalThis.describe("OutboundTranslationSlice Callback", () => {
|
|
|
318
338
|
let mockPublish = async cmds => {
|
|
319
339
|
publishedCommands.contents = publishedCommands.contents.concat(cmds);
|
|
320
340
|
};
|
|
321
|
-
await CommandBackCallback.phase2(mockPublish);
|
|
341
|
+
await CommandBackCallback.phase2(mockPublish, Capabilities$Reventless.none);
|
|
322
342
|
let row1 = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-1"], undefined);
|
|
323
343
|
globalThis.expect(row1.status).toBe("Failed");
|
|
324
344
|
let row2 = Stdlib_Option.getOrThrow(CommandBackCallback.todoItems["ord-2"], undefined);
|
|
@@ -35,7 +35,7 @@ module SendTrackingEmailSpec = {
|
|
|
35
35
|
| OrderShipped({orderId, email}) => [(orderId, {orderId, email})]
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
let translate = async (_id, _item) => Ok(None)
|
|
38
|
+
let translate = async (_id, _item, ~capabilities as _) => Ok(None)
|
|
39
39
|
|
|
40
40
|
let maxRetries = 3
|
|
41
41
|
let heartbeatInterval = 60
|
|
@@ -72,7 +72,10 @@ module ProcessPaymentSpec = {
|
|
|
72
72
|
async (id, _item) => Ok(Some((id, ConfirmPayment({orderId: id}))))
|
|
73
73
|
)
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
// The mock stays two-arg: a test that wants to vary behaviour varies it on
|
|
76
|
+
// the item, and threading capabilities into every fixture would make each
|
|
77
|
+
// one restate a type it does not use.
|
|
78
|
+
let translate = (id, item, ~capabilities as _) => translateFn.contents(id, item)
|
|
76
79
|
|
|
77
80
|
let maxRetries = 2
|
|
78
81
|
let heartbeatInterval = 30
|
|
@@ -47,7 +47,7 @@ function collect(event, param) {
|
|
|
47
47
|
]];
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
async function translate(_id, _item) {
|
|
50
|
+
async function translate(_id, _item, param) {
|
|
51
51
|
return {
|
|
52
52
|
TAG: "Ok",
|
|
53
53
|
_0: undefined
|
|
@@ -113,7 +113,7 @@ let translateFn = {
|
|
|
113
113
|
})
|
|
114
114
|
};
|
|
115
115
|
|
|
116
|
-
function translate$1(id, item) {
|
|
116
|
+
function translate$1(id, item, param) {
|
|
117
117
|
return translateFn.contents(id, item);
|
|
118
118
|
}
|
|
119
119
|
|
package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res
CHANGED
|
@@ -107,7 +107,7 @@ module SendConfirmTranslation: OutboundTranslationSlice.Translation
|
|
|
107
107
|
[(orderId, ({orderId: orderId}: SendConfirmSpec.outboundItem))]
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
let translate = async (_id, item: SendConfirmSpec.outboundItem) => {
|
|
110
|
+
let translate = async (_id, item: SendConfirmSpec.outboundItem, ~capabilities as _) => {
|
|
111
111
|
externalCalls->Array.push(item.orderId)
|
|
112
112
|
Ok(None)
|
|
113
113
|
}
|