@reventlessdev/reventless-local 3.0.0-alpha.241 → 3.0.0-alpha.243
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 +22 -0
- package/package.json +10 -10
- package/src/Platform.res +14 -0
- package/src/Platform.res.mjs +17 -0
- package/src/adapter/LocalCapabilities.res +27 -13
- package/src/adapter/LocalCapabilities.res.mjs +16 -2
- package/src/capability/Capability_Messaging_Log.res +39 -0
- package/src/capability/Capability_Messaging_Log.res.mjs +20 -0
- package/src/components/OutboundTranslationSlice_Builder.res.mjs +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
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.243 (2026-09-02)
|
|
7
|
+
|
|
8
|
+
* feat(aws)!: the messaging sender is configuration, and a stack can choose to only log ([23b8b4b](https://github.com/ReventlessDev/reventless-core/commit/23b8b4bfe9c70555de4d74266ca686cb427485ca))
|
|
9
|
+
|
|
10
|
+
### BREAKING CHANGES
|
|
11
|
+
|
|
12
|
+
* `Capability_Messaging_Ses.make` is replaced by
|
|
13
|
+
`Capability_Messaging.make(~name)`, which reads the transport and the address
|
|
14
|
+
from config; the SES module keeps only `emailSender`. A deployment that named its
|
|
15
|
+
sender in code must move it to `platform:messagingEmailSender` or the deploy is
|
|
16
|
+
refused.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# 3.0.0-alpha.242 (2026-09-01)
|
|
21
|
+
|
|
22
|
+
**Note:** Version bump only for package @reventlessdev/reventless-local
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
# 3.0.0-alpha.241 (2026-09-01)
|
|
7
29
|
|
|
8
30
|
### Bug Fixes
|
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.243",
|
|
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,23 +35,23 @@
|
|
|
35
35
|
"sury": "11.0.0-rc.2",
|
|
36
36
|
"ws": "^8.18.0",
|
|
37
37
|
"@reventlessdev/rescript-effect": "0.1.0-alpha.32",
|
|
38
|
-
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
39
38
|
"@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.27",
|
|
40
|
-
"@reventlessdev/rescript-node": "2.0.0-alpha.8",
|
|
41
39
|
"@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.21",
|
|
40
|
+
"@reventlessdev/rescript-node": "2.0.0-alpha.8",
|
|
41
|
+
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
42
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.254",
|
|
42
43
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19",
|
|
43
|
-
"@reventlessdev/reventless-
|
|
44
|
-
"@reventlessdev/reventless-
|
|
45
|
-
"@reventlessdev/reventless-gwt": "1.0.0-alpha.
|
|
46
|
-
"@reventlessdev/reventless-postgres": "3.0.0-alpha.
|
|
44
|
+
"@reventlessdev/reventless-graphql-server": "1.0.0-alpha.102",
|
|
45
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.155",
|
|
46
|
+
"@reventlessdev/reventless-gwt": "1.0.0-alpha.201",
|
|
47
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.118",
|
|
47
48
|
"@reventlessdev/reventless-seed": "1.0.0-alpha.18",
|
|
48
|
-
"@reventlessdev/reventless-
|
|
49
|
-
"@reventlessdev/reventless-spec": "3.0.0-alpha.125"
|
|
49
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.127"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"rescript": "12.3.0",
|
|
53
53
|
"sury-ppx": "11.0.0-rc.2",
|
|
54
|
-
"@reventlessdev/reventless-ppx": "1.0.0-alpha.
|
|
54
|
+
"@reventlessdev/reventless-ppx": "1.0.0-alpha.76"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"rescript": "12.3.0"
|
package/src/Platform.res
CHANGED
|
@@ -1491,6 +1491,20 @@ module MakeWithConfig = (
|
|
|
1491
1491
|
`backend: sqlite (${path}${resetOnStart ? ", resetOnStart" : ""})`
|
|
1492
1492
|
},
|
|
1493
1493
|
)
|
|
1494
|
+
// The infrastructure half of `~hostUiBundle` that this platform does NOT
|
|
1495
|
+
// ignore. A capability is the one kind of deployment declaration that has a
|
|
1496
|
+
// local counterpart — the slice reaching it runs in this process, so there is
|
|
1497
|
+
// something real to provide — and the seam is the AWS one: a handle from a
|
|
1498
|
+
// `Capability_*` helper, registered before a slice can ask for it. `Input.t`
|
|
1499
|
+
// is the identity function off Pulumi, so what comes back out is the string.
|
|
1500
|
+
switch hostUiBundle->Option.flatMap(cfg => cfg.messagingSender) {
|
|
1501
|
+
| Some({emailSender: ?Some(sender)}) =>
|
|
1502
|
+
let address = sender->Pulumi.Output.fromInput->Pulumi.Output.unwrap
|
|
1503
|
+
LocalCapabilities.registerMessagingSender(address)
|
|
1504
|
+
log.info(~comp="Platform", `messaging: log transport as ${address} (nothing is sent)`)
|
|
1505
|
+
| _ => ()
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1494
1508
|
// Runtime extension seam. Fired before anything is built, so an extension's
|
|
1495
1509
|
// interception and publish hooks are registered before the first command or
|
|
1496
1510
|
// query can reach them.
|
package/src/Platform.res.mjs
CHANGED
|
@@ -52,6 +52,7 @@ import * as Platform_AdminApi$ReventlessCore from "@reventlessdev/reventless-cor
|
|
|
52
52
|
import * as PluginsProjection$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/lifecycle/PluginsProjection.res.mjs";
|
|
53
53
|
import * as Scheduler_Builder$ReventlessCore from "@reventlessdev/reventless-core/src/components/Scheduler/Scheduler_Builder.res.mjs";
|
|
54
54
|
import * as Aggregate_Builder$ReventlessLocal from "./components/Aggregate_Builder.res.mjs";
|
|
55
|
+
import * as LocalCapabilities$ReventlessLocal from "./adapter/LocalCapabilities.res.mjs";
|
|
55
56
|
import * as LocalClonerRunner$ReventlessLocal from "./adapter/Cloner/LocalClonerRunner.res.mjs";
|
|
56
57
|
import * as PluginBaseFragment$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/api/PluginBaseFragment.res.mjs";
|
|
57
58
|
import * as ProjectionPending$ReventlessLocal from "./adapter/ProjectionPending.res.mjs";
|
|
@@ -1230,6 +1231,14 @@ function MakeWithConfig(Config) {
|
|
|
1230
1231
|
) + `)` : `backend: postgres (` + match.connection + `, event-logs only)`
|
|
1231
1232
|
);
|
|
1232
1233
|
log.info("Platform", undefined, tmp);
|
|
1234
|
+
let match$1 = Stdlib_Option.flatMap(hostUiBundle, cfg => cfg.messagingSender);
|
|
1235
|
+
if (match$1 !== undefined) {
|
|
1236
|
+
let sender = match$1.emailSender;
|
|
1237
|
+
if (sender !== undefined) {
|
|
1238
|
+
LocalCapabilities$ReventlessLocal.registerMessagingSender(sender);
|
|
1239
|
+
log.info("Platform", undefined, `messaging: log transport as ` + sender + ` (nothing is sent)`);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1233
1242
|
RuntimeExtension$ReventlessCore.notifyColdStart("Platform", "LocalPlatform", ResourceAttribution$ReventlessCore.current.contents.plugin, ResourceAttribution$ReventlessCore.current.contents.platform);
|
|
1234
1243
|
let projectionCatchup = Stdlib_Option.map(BackendState$ReventlessLocal.getSqliteDb(), db => [
|
|
1235
1244
|
db,
|
|
@@ -2959,6 +2968,14 @@ function Make($star) {
|
|
|
2959
2968
|
) + `)` : `backend: postgres (` + backend.connection + `, event-logs only)`
|
|
2960
2969
|
);
|
|
2961
2970
|
log.info("Platform", undefined, tmp);
|
|
2971
|
+
let match = Stdlib_Option.flatMap(hostUiBundle, cfg => cfg.messagingSender);
|
|
2972
|
+
if (match !== undefined) {
|
|
2973
|
+
let sender = match.emailSender;
|
|
2974
|
+
if (sender !== undefined) {
|
|
2975
|
+
LocalCapabilities$ReventlessLocal.registerMessagingSender(sender);
|
|
2976
|
+
log.info("Platform", undefined, `messaging: log transport as ` + sender + ` (nothing is sent)`);
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2962
2979
|
RuntimeExtension$ReventlessCore.notifyColdStart("Platform", "LocalPlatform", ResourceAttribution$ReventlessCore.current.contents.plugin, ResourceAttribution$ReventlessCore.current.contents.platform);
|
|
2963
2980
|
let projectionCatchup = Stdlib_Option.map(BackendState$ReventlessLocal.getSqliteDb(), db => [
|
|
2964
2981
|
db,
|
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
// What the local platform hands a slice's `translate`.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// its items stay queued, which is true, instead of seeing them written off as
|
|
9
|
-
// unresolvable addresses, which would not be. Messaging additionally publishes an
|
|
10
|
-
// empty channel list, so a preference surface offers nothing rather than offering
|
|
11
|
-
// a channel that cannot deliver.
|
|
3
|
+
// No geocoder: the local platform provisions none (a place index is an account
|
|
4
|
+
// and a bill), so `Capabilities.none`'s `geocode` reports `Unavailable`, which
|
|
5
|
+
// `translate` maps to a retryable `Error` and the sweep surfaces. A dev running a
|
|
6
|
+
// geocoding slice sees its items stay queued, which is true, instead of seeing
|
|
7
|
+
// them written off as unresolvable addresses, which would not be.
|
|
12
8
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
|
|
9
|
+
// Messaging is provisioned when a root asks for it, exactly as on AWS: a
|
|
10
|
+
// `Capability_Messaging_Log.make()` handle passed as `~messagingSender`
|
|
11
|
+
// reaches `registerMessagingSender` and the transport becomes the provider. A root
|
|
12
|
+
// that passes nothing keeps the old answer — an empty sender yields no channels
|
|
13
|
+
// and a retryable `Unavailable`, which is what an unprovisioned platform is.
|
|
14
|
+
//
|
|
15
|
+
// The sender is a ref read per call rather than a value captured once, mirroring
|
|
16
|
+
// the Lambda side: there `capabilities()` re-reads `MESSAGING_EMAIL_SENDER` on
|
|
17
|
+
// every invocation so a reconfigured function needs no cold start. Here it means
|
|
18
|
+
// the order of `makePlatform`'s work is not a thing to get right.
|
|
19
|
+
|
|
20
|
+
let messagingSenderRef = ref("")
|
|
21
|
+
|
|
22
|
+
/** Provision the messaging capability. Called by `makePlatform` from the handle
|
|
23
|
+
a root declared — the local half of the seam whose AWS half is
|
|
24
|
+
`PluginRuntime_Builder.registerMessagingSender`. */
|
|
25
|
+
let registerMessagingSender = (sender: string) => messagingSenderRef := sender
|
|
26
|
+
|
|
27
|
+
let capabilities = (): Reventless.Capabilities.t => {
|
|
28
|
+
geocode: Reventless.Capabilities.none.geocode,
|
|
29
|
+
messaging: ReventlessCore.Messaging_Log_Backend.provider(~sender=messagingSenderRef.contents),
|
|
30
|
+
}
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Capabilities$Reventless from "@reventlessdev/reventless-spec/src/semantic/Capabilities.res.mjs";
|
|
4
|
+
import * as Messaging_Log_Backend$ReventlessCore from "@reventlessdev/reventless-core/src/adapter/Messaging/Messaging_Log_Backend.res.mjs";
|
|
5
|
+
|
|
6
|
+
let messagingSenderRef = {
|
|
7
|
+
contents: ""
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function registerMessagingSender(sender) {
|
|
11
|
+
messagingSenderRef.contents = sender;
|
|
12
|
+
}
|
|
4
13
|
|
|
5
14
|
function capabilities() {
|
|
6
|
-
return
|
|
15
|
+
return {
|
|
16
|
+
geocode: Capabilities$Reventless.none.geocode,
|
|
17
|
+
messaging: Messaging_Log_Backend$ReventlessCore.provider(messagingSenderRef.contents)
|
|
18
|
+
};
|
|
7
19
|
}
|
|
8
20
|
|
|
9
21
|
export {
|
|
22
|
+
messagingSenderRef,
|
|
23
|
+
registerMessagingSender,
|
|
10
24
|
capabilities,
|
|
11
25
|
}
|
|
12
|
-
/*
|
|
26
|
+
/* Messaging_Log_Backend-ReventlessCore Not a pure module */
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// The messaging sender a dev platform provisions — the local counterpart to
|
|
2
|
+
// `Capability_Messaging_Ses`, and reached the same way: a root calls `make`,
|
|
3
|
+
// passes the handle as `~messagingSender` in `~hostUiBundle`, and the platform
|
|
4
|
+
// puts a provider on the capability record every slice's `translate` receives.
|
|
5
|
+
// Nothing about a plugin changes between the two.
|
|
6
|
+
//
|
|
7
|
+
// **The address is hard-coded here, where on AWS it is configuration.** That is
|
|
8
|
+
// the one deliberate difference, and it follows from what the value is for. A
|
|
9
|
+
// verified identity is a per-account fact a repository cannot know, so the AWS
|
|
10
|
+
// helper refuses to invent one; a logged message reaches nobody, so there is
|
|
11
|
+
// nothing to verify, nothing that differs per developer, and nothing a setting
|
|
12
|
+
// would buy. `.test` is reserved for exactly this (RFC 6761) — it can never
|
|
13
|
+
// resolve, so an address escaping into a fixture cannot reach a real inbox.
|
|
14
|
+
|
|
15
|
+
/** The `From:` this platform's mail would carry. Named for the platform rather
|
|
16
|
+
than the shop: what a dev is looking at when they read it is the local
|
|
17
|
+
log transport, and a name that impersonated the deployment would make a screenshot
|
|
18
|
+
of a dev run indistinguishable from one of production. */
|
|
19
|
+
let senderName = "Online Shop (local)"
|
|
20
|
+
let senderAddress = "notifications@online-shop.test"
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
The handle, in the shape the platform config takes.
|
|
24
|
+
|
|
25
|
+
`Pulumi.Input.t` in a platform that runs no Pulumi is not an accident: the field
|
|
26
|
+
belongs to the shared `Platform.messagingSender`, so both platforms carry the
|
|
27
|
+
sender in one type and a root moving between them changes which helper it calls
|
|
28
|
+
and nothing else. `Input.make` is the identity function, so what travels is the
|
|
29
|
+
string.
|
|
30
|
+
|
|
31
|
+
The header is built by `Messaging.fromHeader`, the same function the SES helper
|
|
32
|
+
applies to its verified address — one formatter, so the two platforms cannot
|
|
33
|
+
present the same deployment under two differently-escaped names.
|
|
34
|
+
*/
|
|
35
|
+
let make = (): ReventlessInfra.Platform.messagingSender => {
|
|
36
|
+
emailSender: Pulumi.Input.make(
|
|
37
|
+
Reventless.Messaging.fromHeader(~displayName=Some(senderName), ~address=senderAddress),
|
|
38
|
+
),
|
|
39
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Messaging$Reventless from "@reventlessdev/reventless-spec/src/semantic/Messaging.res.mjs";
|
|
4
|
+
|
|
5
|
+
let senderName = "Online Shop (local)";
|
|
6
|
+
|
|
7
|
+
let senderAddress = "notifications@online-shop.test";
|
|
8
|
+
|
|
9
|
+
function make() {
|
|
10
|
+
return {
|
|
11
|
+
emailSender: Messaging$Reventless.fromHeader(senderName, senderAddress)
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
senderName,
|
|
17
|
+
senderAddress,
|
|
18
|
+
make,
|
|
19
|
+
}
|
|
20
|
+
/* No side effect */
|
|
@@ -33,7 +33,9 @@ function Make(Bus) {
|
|
|
33
33
|
make: QueryDbStorage.make
|
|
34
34
|
})({
|
|
35
35
|
make: QueryDbResolvers.make
|
|
36
|
-
})(EventCollectorChannel)(EventCollectorRuntimeBuilder)(Api)(
|
|
36
|
+
})(EventCollectorChannel)(EventCollectorRuntimeBuilder)(Api)({
|
|
37
|
+
capabilities: LocalCapabilities$ReventlessLocal.capabilities
|
|
38
|
+
});
|
|
37
39
|
let Make$1 = Spec => (Translation => {
|
|
38
40
|
let Inner = CoreMaker.Make(Spec)(Translation);
|
|
39
41
|
return {
|