@reventlessdev/reventless-infra 3.0.0-alpha.100 → 3.0.0-alpha.101
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 +9 -0
- package/package.json +8 -8
- package/src/components/Aggregate.res +5 -1
- package/src/components/AutomationSlice.res +1 -0
- package/src/components/ExtensionPoint.res +5 -0
- package/src/components/InboundTranslationSlice.res +1 -0
- package/src/components/OutboundTranslationSlice.res +1 -0
- package/src/components/Plugin.res +6 -0
- package/src/components/ReadModel.res +1 -0
- package/src/components/StateChangeSlice.res +1 -0
- package/src/components/StateViewSlice.res +1 -0
- package/src/components/Task.res +1 -0
- package/src/types/RuntimeHints.res +41 -0
- package/src/types/RuntimeHints.res.mjs +38 -0
- package/tests/RuntimeHintsTest.res +32 -0
- package/tests/RuntimeHintsTest.res.mjs +46 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
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.101 (2026-07-16)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **aws:** consume per-component runtime hints; fold into shared command Lambdas ([7ba2485](https://github.com/ReventlessDev/reventless-core/commit/7ba248579f2472f2fc847b26033927199353f3e6))
|
|
11
|
+
* **core:** honor per-component runtime hints for ExtensionPoints ([72d0218](https://github.com/ReventlessDev/reventless-core/commit/72d0218ec4f73d6a59230640c9ee4a538e6b8688))
|
|
12
|
+
* **core:** thread per-component runtime hints from plugin.json (spec/infra/core/local) ([a94f419](https://github.com/ReventlessDev/reventless-core/commit/a94f4199c4ac7eeeb24dd0a71d58fb73c1e514e6))
|
|
13
|
+
|
|
14
|
+
|
|
6
15
|
# 3.0.0-alpha.100 (2026-07-15)
|
|
7
16
|
|
|
8
17
|
**Note:** Version bump only for package @reventlessdev/reventless-infra
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-infra",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.101",
|
|
4
4
|
"description": "Infrastructure types for Reventless framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -16,17 +16,17 @@
|
|
|
16
16
|
"sury": "11.0.0-alpha.4",
|
|
17
17
|
"sury-ppx": "11.0.0-alpha.2",
|
|
18
18
|
"uuid": "^13.0.0",
|
|
19
|
-
"@reventlessdev/rescript-
|
|
20
|
-
"@reventlessdev/rescript-
|
|
21
|
-
"@reventlessdev/rescript-
|
|
22
|
-
"@reventlessdev/reventless-spec": "3.0.0-alpha.
|
|
19
|
+
"@reventlessdev/rescript-uuid": "1.1.0-alpha.16",
|
|
20
|
+
"@reventlessdev/rescript-effect": "0.1.0-alpha.28",
|
|
21
|
+
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.16",
|
|
22
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.78"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"rescript": "
|
|
26
|
-
"@reventlessdev/rescript-jest": "1.0.0-alpha.
|
|
25
|
+
"rescript": "12.3.0",
|
|
26
|
+
"@reventlessdev/rescript-jest": "1.0.0-alpha.8"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"rescript": "
|
|
29
|
+
"rescript": "12.3.0"
|
|
30
30
|
},
|
|
31
31
|
"publishConfig": {
|
|
32
32
|
"registry": "https://registry.npmjs.org"
|
|
@@ -65,7 +65,11 @@ module type T = {
|
|
|
65
65
|
module Spec: Reventless.Aggregate.Spec
|
|
66
66
|
type api
|
|
67
67
|
type component
|
|
68
|
-
let make: (
|
|
68
|
+
let make: (
|
|
69
|
+
~api: api,
|
|
70
|
+
~runtime: RuntimeHints.t=?,
|
|
71
|
+
~opts: Pulumi.ComponentResource.options=?,
|
|
72
|
+
) => component
|
|
69
73
|
let outputs: component => outputs
|
|
70
74
|
let operations: component => Pulumi.Output.t<operations>
|
|
71
75
|
/** Signal that all event mappers have been attached; finalises the aggregate. */
|
|
@@ -43,6 +43,7 @@ module type T = {
|
|
|
43
43
|
~allEventTopics: EventTopic.allOutputs,
|
|
44
44
|
~publishJsons: Pulumi.Output.t<CommandTopic.publishJsons>,
|
|
45
45
|
~context: Reventless.AutomationSlice.context,
|
|
46
|
+
~runtime: RuntimeHints.t=?,
|
|
46
47
|
~opts: Pulumi.ComponentResource.options=?,
|
|
47
48
|
) => component
|
|
48
49
|
}
|
|
@@ -49,12 +49,17 @@ the `reventless` package.
|
|
|
49
49
|
module type T = {
|
|
50
50
|
type operations
|
|
51
51
|
type component
|
|
52
|
+
/** The extension point's logical name — the key its `plugin.json` runtime
|
|
53
|
+
hint is looked up by at the `Builder_Helpers.createExtensionPoints` site,
|
|
54
|
+
before `make` is called. */
|
|
55
|
+
let name: string
|
|
52
56
|
let make: (
|
|
53
57
|
~aggregateResources: dict<array<Adapter.resource>>,
|
|
54
58
|
~publishToAggregates: dict<CommandTopic.publishJsons>,
|
|
55
59
|
~scheduler: Scheduler.operations,
|
|
56
60
|
~queryEngine: Reventless.QueryEngine.operations,
|
|
57
61
|
~resourceNaming: ResourceNaming.operations,
|
|
62
|
+
~runtime: RuntimeHints.t=?,
|
|
58
63
|
~opts: option<Pulumi.ComponentResource.options>,
|
|
59
64
|
) => component
|
|
60
65
|
let outputs: component => outputs
|
|
@@ -66,6 +66,12 @@ module type T = {
|
|
|
66
66
|
`@@reventless.systemCallable` on the spec file and threaded here by the
|
|
67
67
|
plugin generator; see `docs/guides/appsync-iam-system-caller.md`. */
|
|
68
68
|
~systemCallableComponents: array<string>=?,
|
|
69
|
+
/** Per-component runtime resource hints keyed by component name, authored in
|
|
70
|
+
the plugin's `plugin.json` `runtime` block and emitted by the plugin
|
|
71
|
+
generator. The deploy loop looks up each component's hint by `Spec.name`
|
|
72
|
+
and forwards it into that component's `make`. See
|
|
73
|
+
docs/plans/configurable-component-runtime-resources.md. */
|
|
74
|
+
~componentRuntime: dict<RuntimeHints.t>=?,
|
|
69
75
|
~uiFragments: Reventless.Plugin.uiFragmentManifest=?,
|
|
70
76
|
~pluginStructure: Reventless.Plugin.pluginStructure=?,
|
|
71
77
|
~opts: Pulumi.ComponentResource.options=?,
|
|
@@ -40,6 +40,7 @@ module type T = {
|
|
|
40
40
|
a cross-partition scalar command tag fans out into its own single-tag
|
|
41
41
|
decision-read clause. */
|
|
42
42
|
~crossPartitionTagKeys: array<string>=?,
|
|
43
|
+
~runtime: RuntimeHints.t=?,
|
|
43
44
|
~opts: Pulumi.ComponentResource.options=?,
|
|
44
45
|
) => component
|
|
45
46
|
}
|
package/src/components/Task.res
CHANGED
|
@@ -83,6 +83,7 @@ module type T = {
|
|
|
83
83
|
~queryEngine: Reventless.QueryEngine.operations,
|
|
84
84
|
~resourceNaming: ResourceNaming.operations,
|
|
85
85
|
~allAggregates: dict<Aggregate.outputs>,
|
|
86
|
+
~runtime: RuntimeHints.t=?,
|
|
86
87
|
~opts: option<Pulumi.ComponentResource.options>,
|
|
87
88
|
) => component
|
|
88
89
|
let outputs: component => outputs
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Per-component runtime resource hints, declared once (portably) on the plugin's
|
|
3
|
+
composition surface (`plugin.json` `runtime` block) and threaded into each
|
|
4
|
+
component's `make` by the plugin deploy loop.
|
|
5
|
+
|
|
6
|
+
Both fields are optional; an omitted field falls through to the per-kind builder
|
|
7
|
+
default. The value is a *logical envelope* (working-set memory / wall-clock),
|
|
8
|
+
not a literal cap — each platform adapter maps it to its own resource model
|
|
9
|
+
(AWS Lambda `memorySize`/`timeout`, k8s pod `requests`/`limits`, local ignores).
|
|
10
|
+
|
|
11
|
+
See docs/plans/configurable-component-runtime-resources.md.
|
|
12
|
+
*/
|
|
13
|
+
type t = {
|
|
14
|
+
memorySize: option<int>,
|
|
15
|
+
timeout: option<int>,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** No hints — every field falls through to the per-kind builder default. */
|
|
19
|
+
let empty: t = {memorySize: None, timeout: None}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
Resolve a component's memory floor: the per-component override raises the
|
|
23
|
+
per-kind default, never lowers it (`Math.Int.max`). An absent override yields
|
|
24
|
+
the default unchanged.
|
|
25
|
+
*/
|
|
26
|
+
let resolveMemory = (hints: option<t>, ~default: int): int =>
|
|
27
|
+
switch hints {
|
|
28
|
+
| Some({memorySize: Some(m)}) => Math.Int.max(default, m)
|
|
29
|
+
| _ => default
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
Resolve a component's timeout: an explicit per-component timeout replaces the
|
|
34
|
+
default (no `max` — a longer default is not inherently safer). An absent
|
|
35
|
+
override yields the default unchanged.
|
|
36
|
+
*/
|
|
37
|
+
let resolveTimeout = (hints: option<t>, ~default: int): int =>
|
|
38
|
+
switch hints {
|
|
39
|
+
| Some({timeout: Some(t)}) => t
|
|
40
|
+
| _ => default
|
|
41
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function resolveMemory(hints, $$default) {
|
|
5
|
+
if (hints === undefined) {
|
|
6
|
+
return $$default;
|
|
7
|
+
}
|
|
8
|
+
let m = hints.memorySize;
|
|
9
|
+
if (m !== undefined) {
|
|
10
|
+
return Math.max($$default, m);
|
|
11
|
+
} else {
|
|
12
|
+
return $$default;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function resolveTimeout(hints, $$default) {
|
|
17
|
+
if (hints === undefined) {
|
|
18
|
+
return $$default;
|
|
19
|
+
}
|
|
20
|
+
let t = hints.timeout;
|
|
21
|
+
if (t !== undefined) {
|
|
22
|
+
return t;
|
|
23
|
+
} else {
|
|
24
|
+
return $$default;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let empty = {
|
|
29
|
+
memorySize: undefined,
|
|
30
|
+
timeout: undefined
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
empty,
|
|
35
|
+
resolveMemory,
|
|
36
|
+
resolveTimeout,
|
|
37
|
+
}
|
|
38
|
+
/* No side effect */
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
open JestGlobals
|
|
2
|
+
|
|
3
|
+
module RH = RuntimeHints
|
|
4
|
+
|
|
5
|
+
// Precedence for per-component runtime hints (see
|
|
6
|
+
// docs/plans/configurable-component-runtime-resources.md): memory is a floor
|
|
7
|
+
// (override raises the per-kind default via Math.Int.max, never lowers it),
|
|
8
|
+
// timeout is a replace (an explicit value wins outright).
|
|
9
|
+
|
|
10
|
+
describe("RuntimeHints.resolveMemory", () => {
|
|
11
|
+
testSync("no hint falls through to the per-kind default", () => {
|
|
12
|
+
expect(RH.resolveMemory(None, ~default=1024))->toBe(1024)
|
|
13
|
+
})
|
|
14
|
+
testSync("an override above the default wins", () => {
|
|
15
|
+
expect(RH.resolveMemory(Some({memorySize: Some(2048), timeout: None}), ~default=1024))->toBe(2048)
|
|
16
|
+
})
|
|
17
|
+
testSync("an override below the default is clamped up to the floor", () => {
|
|
18
|
+
expect(RH.resolveMemory(Some({memorySize: Some(256), timeout: None}), ~default=1024))->toBe(1024)
|
|
19
|
+
})
|
|
20
|
+
testSync("an absent memorySize field falls through to the default", () => {
|
|
21
|
+
expect(RH.resolveMemory(Some({memorySize: None, timeout: Some(60)}), ~default=1024))->toBe(1024)
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe("RuntimeHints.resolveTimeout", () => {
|
|
26
|
+
testSync("an explicit timeout replaces the default (no max)", () => {
|
|
27
|
+
expect(RH.resolveTimeout(Some({memorySize: None, timeout: Some(15)}), ~default=30))->toBe(15)
|
|
28
|
+
})
|
|
29
|
+
testSync("no hint falls through to the default", () => {
|
|
30
|
+
expect(RH.resolveTimeout(None, ~default=30))->toBe(30)
|
|
31
|
+
})
|
|
32
|
+
})
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as RuntimeHints$ReventlessInfra from "../src/types/RuntimeHints.res.mjs";
|
|
4
|
+
|
|
5
|
+
globalThis.describe("RuntimeHints.resolveMemory", () => {
|
|
6
|
+
globalThis.test("no hint falls through to the per-kind default", () => {
|
|
7
|
+
globalThis.expect(RuntimeHints$ReventlessInfra.resolveMemory(undefined, 1024)).toBe(1024);
|
|
8
|
+
});
|
|
9
|
+
globalThis.test("an override above the default wins", () => {
|
|
10
|
+
globalThis.expect(RuntimeHints$ReventlessInfra.resolveMemory({
|
|
11
|
+
memorySize: 2048,
|
|
12
|
+
timeout: undefined
|
|
13
|
+
}, 1024)).toBe(2048);
|
|
14
|
+
});
|
|
15
|
+
globalThis.test("an override below the default is clamped up to the floor", () => {
|
|
16
|
+
globalThis.expect(RuntimeHints$ReventlessInfra.resolveMemory({
|
|
17
|
+
memorySize: 256,
|
|
18
|
+
timeout: undefined
|
|
19
|
+
}, 1024)).toBe(1024);
|
|
20
|
+
});
|
|
21
|
+
globalThis.test("an absent memorySize field falls through to the default", () => {
|
|
22
|
+
globalThis.expect(RuntimeHints$ReventlessInfra.resolveMemory({
|
|
23
|
+
memorySize: undefined,
|
|
24
|
+
timeout: 60
|
|
25
|
+
}, 1024)).toBe(1024);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
globalThis.describe("RuntimeHints.resolveTimeout", () => {
|
|
30
|
+
globalThis.test("an explicit timeout replaces the default (no max)", () => {
|
|
31
|
+
globalThis.expect(RuntimeHints$ReventlessInfra.resolveTimeout({
|
|
32
|
+
memorySize: undefined,
|
|
33
|
+
timeout: 15
|
|
34
|
+
}, 30)).toBe(15);
|
|
35
|
+
});
|
|
36
|
+
globalThis.test("no hint falls through to the default", () => {
|
|
37
|
+
globalThis.expect(RuntimeHints$ReventlessInfra.resolveTimeout(undefined, 30)).toBe(30);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
let RH;
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
RH,
|
|
45
|
+
}
|
|
46
|
+
/* Not a pure module */
|