@reventlessdev/reventless-local 3.0.0-alpha.288 → 3.0.0-alpha.290
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 +20 -0
- package/package.json +10 -10
- package/src/adapter/Webhook/LocalWebhookRegistry.res +64 -0
- package/src/adapter/Webhook/LocalWebhookRegistry.res.mjs +52 -0
- package/src/components/InboundTranslationSlice_Builder.res +10 -1
- package/src/components/InboundTranslationSlice_Builder.res.mjs +9 -1
- package/tests/adapter/InboundTranslationMutationTest.res.mjs +6 -4
- package/tests/components/automationslice/AutomationRescheduleFixtures.res +0 -1
- package/tests/components/automationslice/AutomationRescheduleFixtures.res.mjs +0 -1
- package/tests/components/automationslice/AutomationScheduleFixtures.res +0 -1
- package/tests/components/automationslice/AutomationScheduleFixtures.res.mjs +0 -5
- package/tests/components/automationslice/AutomationSliceFixtures.res +0 -2
- package/tests/components/automationslice/AutomationSliceFixtures.res.mjs +0 -2
- package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +0 -1
- package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res.mjs +0 -1
- package/tests/components/automationslice/AutomationSweepFixtures.res +0 -1
- package/tests/components/automationslice/AutomationSweepFixtures.res.mjs +0 -1
- package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res +0 -1
- package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res.mjs +0 -1
- package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res +2 -0
- package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res.mjs +25 -20
- package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res +3 -0
- package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res.mjs +3 -0
- package/tests/components/inboundtranslationslice/InboundTranslationWebhookTest.res +305 -0
- package/tests/components/inboundtranslationslice/InboundTranslationWebhookTest.res.mjs +473 -0
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res.mjs +0 -2
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res +0 -2
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res.mjs +0 -2
- package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res +0 -1
- package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res.mjs +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
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.290 (2026-10-17)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @reventlessdev/reventless-local
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# 3.0.0-alpha.289 (2026-10-16)
|
|
15
|
+
|
|
16
|
+
* feat!(inbound): a translation slice can declare a signed webhook URL ([0ad6994](https://github.com/ReventlessDev/reventless-core/commit/0ad69949fcc91c2756c60ca8cb120dd468841d8b))
|
|
17
|
+
|
|
18
|
+
### BREAKING CHANGES
|
|
19
|
+
|
|
20
|
+
* InboundTranslationSlice.Spec requires `endpoint`. Specs under
|
|
21
|
+
@@reventless.spec get it from the PPX (republish reventless-ppx with this
|
|
22
|
+
release); hand-written specs add `let endpoint = None`.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
6
26
|
# 3.0.0-alpha.288 (2026-10-16)
|
|
7
27
|
|
|
8
28
|
**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.290",
|
|
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": {
|
|
@@ -34,24 +34,24 @@
|
|
|
34
34
|
"graphql-yoga": "^5.21.0",
|
|
35
35
|
"sury": "11.0.0",
|
|
36
36
|
"ws": "^8.18.0",
|
|
37
|
-
"@reventlessdev/rescript-effect": "1.0.0-alpha.0",
|
|
38
37
|
"@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.29",
|
|
38
|
+
"@reventlessdev/rescript-effect": "1.0.0-alpha.0",
|
|
39
39
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.12",
|
|
40
40
|
"@reventlessdev/rescript-node": "2.0.0-alpha.22",
|
|
41
41
|
"@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.23",
|
|
42
|
-
"@reventlessdev/rescript-pulumi-pulumi": "
|
|
43
|
-
"@reventlessdev/reventless-
|
|
44
|
-
"@reventlessdev/reventless-
|
|
45
|
-
"@reventlessdev/reventless-
|
|
46
|
-
"@reventlessdev/reventless-
|
|
47
|
-
"@reventlessdev/reventless-
|
|
42
|
+
"@reventlessdev/rescript-pulumi-pulumi": "3.0.0-alpha.0",
|
|
43
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.299",
|
|
44
|
+
"@reventlessdev/reventless-graphql-server": "1.0.0-alpha.147",
|
|
45
|
+
"@reventlessdev/reventless-gwt": "1.0.0-alpha.247",
|
|
46
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.163",
|
|
47
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.196",
|
|
48
48
|
"@reventlessdev/reventless-seed": "1.0.0-alpha.34",
|
|
49
|
-
"@reventlessdev/reventless-spec": "3.0.0-alpha.
|
|
49
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.168"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"rescript": "12.3.1",
|
|
53
53
|
"sury-ppx": "11.0.0",
|
|
54
|
-
"@reventlessdev/reventless-ppx": "1.0.0-alpha.
|
|
54
|
+
"@reventlessdev/reventless-ppx": "1.0.0-alpha.103"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"rescript": "^12.3.1"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// The local platform's webhook routes, served in process: no HTTP server, so a
|
|
2
|
+
// test (or a dev tool) posts a raw body with `post`, which runs the same
|
|
3
|
+
// signature check and dispatch as the AWS Function URL.
|
|
4
|
+
|
|
5
|
+
open ReventlessCore
|
|
6
|
+
|
|
7
|
+
let slices: dict<InboundTranslationSlice_Webhook.slice> = Dict.make()
|
|
8
|
+
|
|
9
|
+
/** Register a slice's route now, and bind its operations when they resolve. A
|
|
10
|
+
request posted before then waits for them rather than failing. Two slices may
|
|
11
|
+
not share a path. */
|
|
12
|
+
let register = (
|
|
13
|
+
~route: InboundTranslationSlice_Webhook.route,
|
|
14
|
+
~operations: Pulumi.Output.t<ReventlessInfra.InboundTranslationSlice.operations>,
|
|
15
|
+
) => {
|
|
16
|
+
switch slices->Dict.get(route.path) {
|
|
17
|
+
| Some({route: taken}) =>
|
|
18
|
+
JsError.throwWithMessage(
|
|
19
|
+
`webhook path /${route.path} is declared by both ${taken.slice} and ${route.slice}`,
|
|
20
|
+
)
|
|
21
|
+
| None => ()
|
|
22
|
+
}
|
|
23
|
+
let bind = ref(_ => ())
|
|
24
|
+
let bound: promise<ReventlessInfra.InboundTranslationSlice.operations> = Promise.make((
|
|
25
|
+
resolve,
|
|
26
|
+
_,
|
|
27
|
+
) => bind := resolve)
|
|
28
|
+
let _ = operations->Pulumi.Output.apply(ops => bind.contents(ops))
|
|
29
|
+
slices->Dict.set(
|
|
30
|
+
route.path,
|
|
31
|
+
{
|
|
32
|
+
route,
|
|
33
|
+
receive: async (input, ~caller) => await (await bound).receive(input, ~caller, ~door=Webhook),
|
|
34
|
+
refuse: async (~body, ~errorCode, error) =>
|
|
35
|
+
await (await bound).refuse(~body, ~errorCode, error),
|
|
36
|
+
},
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Serve one request. Header names are matched case-insensitively. */
|
|
41
|
+
let post = (
|
|
42
|
+
~path: string,
|
|
43
|
+
~method: string="POST",
|
|
44
|
+
~headers: dict<string>=Dict.make(),
|
|
45
|
+
~secretOf=?,
|
|
46
|
+
~nowSeconds=?,
|
|
47
|
+
body: string,
|
|
48
|
+
): promise<InboundTranslationSlice_Webhook.response> =>
|
|
49
|
+
InboundTranslationSlice_Webhook.dispatch(
|
|
50
|
+
slices->Dict.valuesToArray,
|
|
51
|
+
~secretOf?,
|
|
52
|
+
~nowSeconds?,
|
|
53
|
+
{
|
|
54
|
+
method,
|
|
55
|
+
path,
|
|
56
|
+
headers: headers
|
|
57
|
+
->Dict.toArray
|
|
58
|
+
->Array.map(((name, value)) => (name->String.toLowerCase, value))
|
|
59
|
+
->Dict.fromArray,
|
|
60
|
+
body,
|
|
61
|
+
},
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
let reset = () => slices->Dict.keysToArray->Array.forEach(path => slices->Dict.delete(path))
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
4
|
+
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
5
|
+
import * as InboundTranslationSlice_Webhook$ReventlessCore from "@reventlessdev/reventless-core/src/components/InboundTranslationSlice/InboundTranslationSlice_Webhook.res.mjs";
|
|
6
|
+
|
|
7
|
+
let slices = {};
|
|
8
|
+
|
|
9
|
+
function register(route, operations) {
|
|
10
|
+
let match = slices[route.path];
|
|
11
|
+
if (match !== undefined) {
|
|
12
|
+
Stdlib_JsError.throwWithMessage(`webhook path /` + route.path + ` is declared by both ` + match.route.slice + ` and ` + route.slice);
|
|
13
|
+
}
|
|
14
|
+
let bind = {
|
|
15
|
+
contents: param => {}
|
|
16
|
+
};
|
|
17
|
+
let bound = new Promise((resolve, param) => {
|
|
18
|
+
bind.contents = resolve;
|
|
19
|
+
});
|
|
20
|
+
operations.apply(ops => bind.contents(ops));
|
|
21
|
+
slices[route.path] = {
|
|
22
|
+
route: route,
|
|
23
|
+
receive: async (input, caller) => await (await bound).receive(input, caller, "Webhook"),
|
|
24
|
+
refuse: async (body, errorCode, error) => await (await bound).refuse(body, errorCode, error)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function post(path, methodOpt, headersOpt, secretOf, nowSeconds, body) {
|
|
29
|
+
let method = methodOpt !== undefined ? methodOpt : "POST";
|
|
30
|
+
let headers = headersOpt !== undefined ? headersOpt : ({});
|
|
31
|
+
return InboundTranslationSlice_Webhook$ReventlessCore.dispatch(Object.values(slices), secretOf, nowSeconds, {
|
|
32
|
+
method: method,
|
|
33
|
+
path: path,
|
|
34
|
+
headers: Object.fromEntries(Object.entries(headers).map(param => [
|
|
35
|
+
param[0].toLowerCase(),
|
|
36
|
+
param[1]
|
|
37
|
+
])),
|
|
38
|
+
body: body
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function reset() {
|
|
43
|
+
Object.keys(slices).forEach(path => Stdlib_Dict.$$delete(slices, path));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export {
|
|
47
|
+
slices,
|
|
48
|
+
register,
|
|
49
|
+
post,
|
|
50
|
+
reset,
|
|
51
|
+
}
|
|
52
|
+
/* InboundTranslationSlice_Webhook-ReventlessCore Not a pure module */
|
|
@@ -26,7 +26,16 @@ module Make = (Bus: LocalBus.T) => {
|
|
|
26
26
|
module Translation = Translation
|
|
27
27
|
type component = Inner.component
|
|
28
28
|
let queryDbName = Inner.queryDbName
|
|
29
|
-
let make =
|
|
29
|
+
let make = (~publishJsons, ~runtime=?, ~opts=?) => {
|
|
30
|
+
let component = Inner.make(~publishJsons, ~runtime?, ~opts?)
|
|
31
|
+
Spec.endpoint->Option.forEach(endpoint =>
|
|
32
|
+
LocalWebhookRegistry.register(
|
|
33
|
+
~route=ReventlessCore.InboundTranslationSlice_Webhook.routeOf(~slice=Spec.name, endpoint),
|
|
34
|
+
~operations=component->ReventlessCore.Component.operations,
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
component
|
|
38
|
+
}
|
|
30
39
|
// Re-expose operations for test resolution
|
|
31
40
|
let operations: component => Pulumi.Output.t<
|
|
32
41
|
ReventlessCore.InboundTranslationSlice.operations,
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
3
4
|
import * as Component$ReventlessCore from "@reventlessdev/reventless-core/src/components/Component.res.mjs";
|
|
4
5
|
import * as LocalQueryDbStorage$ReventlessLocal from "../adapter/QueryDb/LocalQueryDbStorage.res.mjs";
|
|
6
|
+
import * as LocalWebhookRegistry$ReventlessLocal from "../adapter/Webhook/LocalWebhookRegistry.res.mjs";
|
|
5
7
|
import * as QueryDbResolvers_GraphQL$ReventlessLocal from "../adapter/QueryDb/QueryDbResolvers_GraphQL.res.mjs";
|
|
6
8
|
import * as InboundTranslationSlice_Builder$ReventlessCore from "@reventlessdev/reventless-core/src/components/InboundTranslationSlice/InboundTranslationSlice_Builder.res.mjs";
|
|
9
|
+
import * as InboundTranslationSlice_Webhook$ReventlessCore from "@reventlessdev/reventless-core/src/components/InboundTranslationSlice/InboundTranslationSlice_Webhook.res.mjs";
|
|
7
10
|
|
|
8
11
|
function Make(Bus) {
|
|
9
12
|
let QueryDbStorage = LocalQueryDbStorage$ReventlessLocal.Make(Bus);
|
|
@@ -21,12 +24,17 @@ function Make(Bus) {
|
|
|
21
24
|
})(Api);
|
|
22
25
|
let Make$1 = Spec => (Translation => {
|
|
23
26
|
let Inner = CoreMaker.Make(Spec)(Translation);
|
|
27
|
+
let make = (publishJsons, runtime, opts) => {
|
|
28
|
+
let component = Inner.make(publishJsons, runtime, opts);
|
|
29
|
+
Stdlib_Option.forEach(Spec.endpoint, endpoint => LocalWebhookRegistry$ReventlessLocal.register(InboundTranslationSlice_Webhook$ReventlessCore.routeOf(Spec.name, endpoint), Component$ReventlessCore.operations(component)));
|
|
30
|
+
return component;
|
|
31
|
+
};
|
|
24
32
|
return {
|
|
25
33
|
Inner: Inner,
|
|
26
34
|
Spec: Spec,
|
|
27
35
|
Translation: Translation,
|
|
28
36
|
queryDbName: Inner.queryDbName,
|
|
29
|
-
make:
|
|
37
|
+
make: make,
|
|
30
38
|
operations: Component$ReventlessCore.operations
|
|
31
39
|
};
|
|
32
40
|
});
|
|
@@ -29,7 +29,8 @@ let Callback = InboundTranslationSlice_Callback$ReventlessCore.Make({
|
|
|
29
29
|
commandSchema: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.commandSchema,
|
|
30
30
|
targetName: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.targetName,
|
|
31
31
|
externalSystem: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.externalSystem,
|
|
32
|
-
authorizationOf: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.authorizationOf
|
|
32
|
+
authorizationOf: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.authorizationOf,
|
|
33
|
+
endpoint: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.endpoint
|
|
33
34
|
})(PaymentWebhookTranslation);
|
|
34
35
|
|
|
35
36
|
let scope = "Payments";
|
|
@@ -106,7 +107,7 @@ globalThis.describe("InboundTranslationSlice mutation — response envelope", ()
|
|
|
106
107
|
DomainGraphQL_Server$ReventlessLocal.setScope(scope);
|
|
107
108
|
InboundTranslationResolvers_GraphQL$ReventlessLocal.register(fieldName, InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.externalInputSchema, "AllowAuthenticated", DomainGraphQL_Server$ReventlessLocal.asInterface);
|
|
108
109
|
DomainGraphQL_Server$ReventlessLocal.resetScope();
|
|
109
|
-
InboundTranslationResolvers_GraphQL$ReventlessLocal.bindReceive(fieldName, (inputJson, caller) => Callback.receive(publishJsons, inputJson, caller));
|
|
110
|
+
InboundTranslationResolvers_GraphQL$ReventlessLocal.bindReceive(fieldName, (inputJson, caller) => Callback.receive(publishJsons, inputJson, caller, undefined));
|
|
110
111
|
});
|
|
111
112
|
globalThis.test("a successful translation resolves as CommandAccepted, with no errors", async () => {
|
|
112
113
|
let result = await runMutation("completed");
|
|
@@ -157,7 +158,8 @@ let CatalogFeedCallback = InboundTranslationSlice_Callback$ReventlessCore.Make({
|
|
|
157
158
|
commandSchema: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.commandSchema,
|
|
158
159
|
targetName: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.targetName,
|
|
159
160
|
externalSystem: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.externalSystem,
|
|
160
|
-
authorizationOf: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.authorizationOf
|
|
161
|
+
authorizationOf: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.authorizationOf,
|
|
162
|
+
endpoint: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.endpoint
|
|
161
163
|
})(CatalogFeedTranslation);
|
|
162
164
|
|
|
163
165
|
let feedField = "Catalog_CatalogFeed";
|
|
@@ -173,7 +175,7 @@ globalThis.describe("InboundTranslationSlice mutation — the door", () => {
|
|
|
173
175
|
DomainGraphQL_Server$ReventlessLocal.setScope("Catalog");
|
|
174
176
|
InboundTranslationResolvers_GraphQL$ReventlessLocal.register(feedField, InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.externalInputSchema, Dcb_Builder$ReventlessCore.inboundDoorPermission(InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.commandSchema, InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.authorizationOf), DomainGraphQL_Server$ReventlessLocal.asInterface);
|
|
175
177
|
DomainGraphQL_Server$ReventlessLocal.resetScope();
|
|
176
|
-
InboundTranslationResolvers_GraphQL$ReventlessLocal.bindReceive(feedField, (inputJson, caller) => CatalogFeedCallback.receive(publishJsons, inputJson, caller));
|
|
178
|
+
InboundTranslationResolvers_GraphQL$ReventlessLocal.bindReceive(feedField, (inputJson, caller) => CatalogFeedCallback.receive(publishJsons, inputJson, caller, undefined));
|
|
177
179
|
});
|
|
178
180
|
globalThis.test("a caller holding none of the commands' roles is refused", async () => {
|
|
179
181
|
let node = payload(await runFeed(signedIn(["Ops"]), "product"));
|
|
@@ -54,7 +54,6 @@ let DemandReportSpec = {
|
|
|
54
54
|
todoItemSchema: todoItemSchema,
|
|
55
55
|
commandSchema: commandSchema,
|
|
56
56
|
maxRetries: 2,
|
|
57
|
-
heartbeatInterval: 60,
|
|
58
57
|
targetName: targetName,
|
|
59
58
|
schedule: DemandReportSpec_schedule,
|
|
60
59
|
authorizationOf: authorizationOf,
|
|
@@ -124,7 +123,6 @@ let UnscheduledSpec = {
|
|
|
124
123
|
todoItemSchema: todoItemSchema,
|
|
125
124
|
commandSchema: commandSchema,
|
|
126
125
|
maxRetries: 2,
|
|
127
|
-
heartbeatInterval: 60,
|
|
128
126
|
targetName: targetName,
|
|
129
127
|
authorizationOf: authorizationOf,
|
|
130
128
|
commandTransition: commandTransition,
|
|
@@ -155,7 +153,6 @@ let FromClockUnscheduled = AutomationSlice$Reventless.Mapping.Make({
|
|
|
155
153
|
todoItemSchema: todoItemSchema,
|
|
156
154
|
commandSchema: commandSchema,
|
|
157
155
|
maxRetries: 2,
|
|
158
|
-
heartbeatInterval: 60,
|
|
159
156
|
targetName: targetName,
|
|
160
157
|
schedule: undefined
|
|
161
158
|
})({
|
|
@@ -180,7 +177,6 @@ AutomationSlice$Reventless.Mappings.Make({
|
|
|
180
177
|
todoItemSchema: todoItemSchema,
|
|
181
178
|
commandSchema: commandSchema,
|
|
182
179
|
maxRetries: 2,
|
|
183
|
-
heartbeatInterval: 60,
|
|
184
180
|
targetName: targetName,
|
|
185
181
|
schedule: undefined
|
|
186
182
|
});
|
|
@@ -208,7 +204,6 @@ let Unscheduled = AutomationSliceMaker.Make({
|
|
|
208
204
|
todoItemSchema: todoItemSchema,
|
|
209
205
|
commandSchema: commandSchema,
|
|
210
206
|
maxRetries: 2,
|
|
211
|
-
heartbeatInterval: 60,
|
|
212
207
|
targetName: targetName,
|
|
213
208
|
schedule: undefined
|
|
214
209
|
})(UnscheduledAutomation);
|
|
@@ -39,7 +39,6 @@ module ShipOrderSpec = {
|
|
|
39
39
|
type command = CreateShipment({orderId: @s.matches(Reventless.DcbTag.string) string})
|
|
40
40
|
|
|
41
41
|
let maxRetries = 3
|
|
42
|
-
let heartbeatInterval = 60
|
|
43
42
|
let targetName = "CreateShipment"
|
|
44
43
|
let schedule = None
|
|
45
44
|
}
|
|
@@ -55,7 +54,6 @@ module SkipProcessSpec = {
|
|
|
55
54
|
type command = Noop
|
|
56
55
|
|
|
57
56
|
let maxRetries = 0
|
|
58
|
-
let heartbeatInterval = 60
|
|
59
57
|
let targetName = "Noop"
|
|
60
58
|
let schedule = None
|
|
61
59
|
}
|
|
@@ -75,7 +75,6 @@ let ShipOrderSpec = {
|
|
|
75
75
|
todoItemSchema: todoItemSchema,
|
|
76
76
|
commandSchema: commandSchema,
|
|
77
77
|
maxRetries: 3,
|
|
78
|
-
heartbeatInterval: 60,
|
|
79
78
|
targetName: "CreateShipment",
|
|
80
79
|
schedule: undefined,
|
|
81
80
|
authorizationOf: authorizationOf,
|
|
@@ -107,7 +106,6 @@ let SkipProcessSpec = {
|
|
|
107
106
|
todoItemSchema: todoItemSchema$1,
|
|
108
107
|
commandSchema: commandSchema$1,
|
|
109
108
|
maxRetries: 0,
|
|
110
|
-
heartbeatInterval: 60,
|
|
111
109
|
targetName: "Noop",
|
|
112
110
|
schedule: undefined,
|
|
113
111
|
authorizationOf: authorizationOf$1,
|
|
@@ -215,6 +215,7 @@ describe("InboundTranslationSlice Callback", () => {
|
|
|
215
215
|
|
|
216
216
|
let targetName = "ConfirmPayment"
|
|
217
217
|
let externalSystem = None
|
|
218
|
+
let endpoint = None
|
|
218
219
|
|
|
219
220
|
let translate = (input: externalInput) => Ok(
|
|
220
221
|
input.items->Array.map(
|
|
@@ -285,6 +286,7 @@ describe("InboundTranslationSlice Callback", () => {
|
|
|
285
286
|
|
|
286
287
|
let targetName = "ConfirmPayment"
|
|
287
288
|
let externalSystem = None
|
|
289
|
+
let endpoint = None
|
|
288
290
|
|
|
289
291
|
let translate = (_input: externalInput) => Ok([])
|
|
290
292
|
|
package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res.mjs
CHANGED
|
@@ -26,7 +26,8 @@ let Callback = InboundTranslationSlice_Callback$ReventlessCore.Make({
|
|
|
26
26
|
commandSchema: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.commandSchema,
|
|
27
27
|
targetName: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.targetName,
|
|
28
28
|
externalSystem: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.externalSystem,
|
|
29
|
-
authorizationOf: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.authorizationOf
|
|
29
|
+
authorizationOf: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.authorizationOf,
|
|
30
|
+
endpoint: InboundTranslationSliceFixtures$ReventlessLocal.PaymentWebhookSpec.endpoint
|
|
30
31
|
})(PaymentWebhookTranslation);
|
|
31
32
|
|
|
32
33
|
globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
@@ -46,7 +47,7 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
46
47
|
orderId: "ord-1",
|
|
47
48
|
status: "completed"
|
|
48
49
|
};
|
|
49
|
-
let result = await Callback.receive(mockPublish, inputJson, undefined);
|
|
50
|
+
let result = await Callback.receive(mockPublish, inputJson, undefined, undefined);
|
|
50
51
|
if (result.TAG === "Ok") {
|
|
51
52
|
let match = result._0;
|
|
52
53
|
globalThis.expect(match.targetIds).toEqual(["ord-1"]);
|
|
@@ -77,7 +78,7 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
77
78
|
orderId: "ord-1",
|
|
78
79
|
status: "pending"
|
|
79
80
|
};
|
|
80
|
-
let result = await Callback.receive(mockPublish, inputJson, undefined);
|
|
81
|
+
let result = await Callback.receive(mockPublish, inputJson, undefined, undefined);
|
|
81
82
|
if (result.TAG === "Ok") {
|
|
82
83
|
globalThis.expect(true).toBe(false);
|
|
83
84
|
} else {
|
|
@@ -94,7 +95,7 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
94
95
|
let inputJson = {
|
|
95
96
|
unexpected: "data"
|
|
96
97
|
};
|
|
97
|
-
let result = await Callback.receive(mockPublish, inputJson, undefined);
|
|
98
|
+
let result = await Callback.receive(mockPublish, inputJson, undefined, undefined);
|
|
98
99
|
if (result.TAG === "Ok") {
|
|
99
100
|
globalThis.expect(true).toBe(false);
|
|
100
101
|
} else {
|
|
@@ -112,7 +113,7 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
112
113
|
orderId: "ord-1",
|
|
113
114
|
status: "completed"
|
|
114
115
|
};
|
|
115
|
-
let result = await Callback.receive(failingPublish, inputJson, undefined);
|
|
116
|
+
let result = await Callback.receive(failingPublish, inputJson, undefined, undefined);
|
|
116
117
|
if (result.TAG === "Ok") {
|
|
117
118
|
globalThis.expect(true).toBe(false);
|
|
118
119
|
} else {
|
|
@@ -131,7 +132,7 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
131
132
|
paymentId: "pay-1",
|
|
132
133
|
orderId: "ord-1",
|
|
133
134
|
status: "completed"
|
|
134
|
-
}, undefined);
|
|
135
|
+
}, undefined, undefined);
|
|
135
136
|
let firstId = InboundTranslationSlice_Callback$ReventlessCore.requestIdOf(first);
|
|
136
137
|
globalThis.expect(Stdlib_Option.isSome(InboundTranslationSlice_Callback$ReventlessCore.takeAuditRow(Callback.auditLog, firstId))).toBe(true);
|
|
137
138
|
globalThis.expect(Object.entries(Callback.auditLog).length).toBe(0);
|
|
@@ -139,7 +140,7 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
139
140
|
paymentId: "pay-1",
|
|
140
141
|
orderId: "ord-1",
|
|
141
142
|
status: "completed"
|
|
142
|
-
}, undefined);
|
|
143
|
+
}, undefined, undefined);
|
|
143
144
|
let secondId = InboundTranslationSlice_Callback$ReventlessCore.requestIdOf(second);
|
|
144
145
|
globalThis.expect(secondId === firstId).toBe(false);
|
|
145
146
|
globalThis.expect(Object.entries(Callback.auditLog).length).toBe(1);
|
|
@@ -152,7 +153,7 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
152
153
|
paymentId: "pay-1",
|
|
153
154
|
orderId: "ord-1",
|
|
154
155
|
status: "pending"
|
|
155
|
-
}, undefined);
|
|
156
|
+
}, undefined, undefined);
|
|
156
157
|
let id = InboundTranslationSlice_Callback$ReventlessCore.requestIdOf(result);
|
|
157
158
|
let row = InboundTranslationSlice_Callback$ReventlessCore.takeAuditRow(Callback.auditLog, id);
|
|
158
159
|
if (row !== undefined) {
|
|
@@ -198,7 +199,8 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
198
199
|
commandSchema: commandSchema,
|
|
199
200
|
targetName: "ConfirmPayment",
|
|
200
201
|
externalSystem: undefined,
|
|
201
|
-
authorizationOf: authorizationOf
|
|
202
|
+
authorizationOf: authorizationOf,
|
|
203
|
+
endpoint: undefined
|
|
202
204
|
})(MultiTranslation);
|
|
203
205
|
let publishedCommands = {
|
|
204
206
|
contents: []
|
|
@@ -214,7 +216,7 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
214
216
|
"pay-3"
|
|
215
217
|
]
|
|
216
218
|
};
|
|
217
|
-
let result = await MultiCallback.receive(mockPublish, inputJson, undefined);
|
|
219
|
+
let result = await MultiCallback.receive(mockPublish, inputJson, undefined, undefined);
|
|
218
220
|
if (result.TAG === "Ok") {
|
|
219
221
|
let match = result._0;
|
|
220
222
|
globalThis.expect(match.targetIds).toEqual([
|
|
@@ -260,7 +262,8 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
260
262
|
commandSchema: commandSchema,
|
|
261
263
|
targetName: "ConfirmPayment",
|
|
262
264
|
externalSystem: undefined,
|
|
263
|
-
authorizationOf: authorizationOf
|
|
265
|
+
authorizationOf: authorizationOf,
|
|
266
|
+
endpoint: undefined
|
|
264
267
|
})(EmptyTranslation);
|
|
265
268
|
let publishedCommands = {
|
|
266
269
|
contents: []
|
|
@@ -271,7 +274,7 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
271
274
|
let inputJson = {
|
|
272
275
|
orderId: "ord-1"
|
|
273
276
|
};
|
|
274
|
-
let result = await EmptyCallback.receive(mockPublish, inputJson, undefined);
|
|
277
|
+
let result = await EmptyCallback.receive(mockPublish, inputJson, undefined, undefined);
|
|
275
278
|
if (result.TAG === "Ok") {
|
|
276
279
|
let match = result._0;
|
|
277
280
|
globalThis.expect(match.targetIds).toEqual([]);
|
|
@@ -300,7 +303,8 @@ let CatalogFeedCallback = InboundTranslationSlice_Callback$ReventlessCore.Make({
|
|
|
300
303
|
commandSchema: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.commandSchema,
|
|
301
304
|
targetName: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.targetName,
|
|
302
305
|
externalSystem: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.externalSystem,
|
|
303
|
-
authorizationOf: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.authorizationOf
|
|
306
|
+
authorizationOf: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.authorizationOf,
|
|
307
|
+
endpoint: InboundTranslationSliceFixtures$ReventlessLocal.CatalogFeedSpec.endpoint
|
|
304
308
|
})(CatalogFeedTranslation);
|
|
305
309
|
|
|
306
310
|
function caller(groups) {
|
|
@@ -336,7 +340,7 @@ globalThis.describe("receive checks each command against its own rule", () => {
|
|
|
336
340
|
published.contents = [];
|
|
337
341
|
});
|
|
338
342
|
globalThis.test("a caller lacking one command's role is refused, and nothing is published", async () => {
|
|
339
|
-
let result = await CatalogFeedCallback.receive(publish, catalogInput("both"), caller(["Merchandiser"]));
|
|
343
|
+
let result = await CatalogFeedCallback.receive(publish, catalogInput("both"), caller(["Merchandiser"]), undefined);
|
|
340
344
|
if (result.TAG === "Ok") {
|
|
341
345
|
globalThis.expect(true).toBe(false);
|
|
342
346
|
} else {
|
|
@@ -351,22 +355,22 @@ globalThis.describe("receive checks each command against its own rule", () => {
|
|
|
351
355
|
let result = await CatalogFeedCallback.receive(publish, catalogInput("both"), caller([
|
|
352
356
|
"Merchandiser",
|
|
353
357
|
"Admin"
|
|
354
|
-
]));
|
|
358
|
+
]), undefined);
|
|
355
359
|
globalThis.expect(Stdlib_Result.isOk(result)).toBe(true);
|
|
356
360
|
globalThis.expect(published.contents.length).toBe(2);
|
|
357
361
|
});
|
|
358
362
|
globalThis.test("the role one command needs is enough when the input yields only it", async () => {
|
|
359
|
-
let result = await CatalogFeedCallback.receive(publish, catalogInput("product"), caller(["Merchandiser"]));
|
|
363
|
+
let result = await CatalogFeedCallback.receive(publish, catalogInput("product"), caller(["Merchandiser"]), undefined);
|
|
360
364
|
globalThis.expect(Stdlib_Result.isOk(result)).toBe(true);
|
|
361
365
|
globalThis.expect(published.contents.length).toBe(1);
|
|
362
366
|
});
|
|
363
367
|
globalThis.test("no caller is the platform itself, and publishes", async () => {
|
|
364
|
-
let result = await CatalogFeedCallback.receive(publish, catalogInput("both"), undefined);
|
|
368
|
+
let result = await CatalogFeedCallback.receive(publish, catalogInput("both"), undefined, undefined);
|
|
365
369
|
globalThis.expect(Stdlib_Result.isOk(result)).toBe(true);
|
|
366
370
|
globalThis.expect(published.contents.length).toBe(2);
|
|
367
371
|
});
|
|
368
372
|
globalThis.test("a refusal answers CommandRejected with Forbidden", async () => {
|
|
369
|
-
let result = await CatalogFeedCallback.receive(publish, catalogInput("both"), Identity$Reventless.anonymous);
|
|
373
|
+
let result = await CatalogFeedCallback.receive(publish, catalogInput("both"), Identity$Reventless.anonymous, undefined);
|
|
370
374
|
let match = InboundTranslationSlice_Callback$ReventlessCore.receiveResultToOutcome(result);
|
|
371
375
|
switch (match.TAG) {
|
|
372
376
|
case "Rejected" :
|
|
@@ -396,7 +400,8 @@ let NoteFeedCallback = InboundTranslationSlice_Callback$ReventlessCore.Make({
|
|
|
396
400
|
commandSchema: InboundTranslationSliceFixtures$ReventlessLocal.NoteFeedSpec.commandSchema,
|
|
397
401
|
targetName: InboundTranslationSliceFixtures$ReventlessLocal.NoteFeedSpec.targetName,
|
|
398
402
|
externalSystem: InboundTranslationSliceFixtures$ReventlessLocal.NoteFeedSpec.externalSystem,
|
|
399
|
-
authorizationOf: InboundTranslationSliceFixtures$ReventlessLocal.NoteFeedSpec.authorizationOf
|
|
403
|
+
authorizationOf: InboundTranslationSliceFixtures$ReventlessLocal.NoteFeedSpec.authorizationOf,
|
|
404
|
+
endpoint: InboundTranslationSliceFixtures$ReventlessLocal.NoteFeedSpec.endpoint
|
|
400
405
|
})(NoteFeedTranslation);
|
|
401
406
|
|
|
402
407
|
globalThis.describe("receive encodes commands with their schema", () => {
|
|
@@ -410,7 +415,7 @@ globalThis.describe("receive encodes commands with their schema", () => {
|
|
|
410
415
|
await NoteFeedCallback.receive(publish, Object.fromEntries([[
|
|
411
416
|
"orderId",
|
|
412
417
|
"ord-1"
|
|
413
|
-
]]), undefined);
|
|
418
|
+
]]), undefined, undefined);
|
|
414
419
|
let commandJson = published.contents[0].commandJson;
|
|
415
420
|
let decoded = Sury.parseOrThrow(commandJson, InboundTranslationSliceFixtures$ReventlessLocal.NoteFeedSpec.commandSchema);
|
|
416
421
|
globalThis.expect(decoded).toEqual({
|
|
@@ -28,6 +28,7 @@ module PaymentWebhookSpec = {
|
|
|
28
28
|
|
|
29
29
|
let targetName = "ConfirmPayment"
|
|
30
30
|
let externalSystem = None
|
|
31
|
+
let endpoint = None
|
|
31
32
|
|
|
32
33
|
let translate = (input: externalInput) =>
|
|
33
34
|
switch input.status {
|
|
@@ -52,6 +53,7 @@ module CatalogFeedSpec = {
|
|
|
52
53
|
|
|
53
54
|
let targetName = "AddProduct"
|
|
54
55
|
let externalSystem = None
|
|
56
|
+
let endpoint = None
|
|
55
57
|
|
|
56
58
|
type role = Reventless.Role.name
|
|
57
59
|
let merchandiser = Reventless.Role.make("Merchandiser")
|
|
@@ -89,6 +91,7 @@ module NoteFeedSpec = {
|
|
|
89
91
|
|
|
90
92
|
let targetName = "Annotate"
|
|
91
93
|
let externalSystem = None
|
|
94
|
+
let endpoint = None
|
|
92
95
|
|
|
93
96
|
let translate = (input: externalInput) => Ok([
|
|
94
97
|
(input.orderId, Annotate({orderId: input.orderId, note: None})),
|