@reventlessdev/reventless-aws 3.0.0-alpha.406 → 3.0.0-alpha.407

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 CHANGED
@@ -3,6 +3,14 @@
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.407 (2026-10-29)
7
+
8
+ **Note:** Version bump only for package @reventlessdev/reventless-aws
9
+
10
+
11
+
12
+
13
+
6
14
  # 3.0.0-alpha.406 (2026-10-29)
7
15
 
8
16
  **Note:** Version bump only for package @reventlessdev/reventless-aws
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-aws",
3
- "version": "3.0.0-alpha.406",
3
+ "version": "3.0.0-alpha.407",
4
4
  "description": "AWS adapters for Reventless",
5
5
  "license": "Apache-2.0",
6
6
  "bin": {
@@ -23,18 +23,18 @@
23
23
  "uuid": "^13.0.0",
24
24
  "yaml": "^2.8.3",
25
25
  "@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.37",
26
- "@reventlessdev/rescript-jest": "1.0.0-alpha.13",
27
26
  "@reventlessdev/rescript-effect": "1.0.0-alpha.1",
28
- "@reventlessdev/rescript-node": "2.0.0-alpha.24",
27
+ "@reventlessdev/rescript-jest": "1.0.0-alpha.13",
29
28
  "@reventlessdev/rescript-pulumi-aws": "3.0.0-alpha.36",
29
+ "@reventlessdev/rescript-node": "2.0.0-alpha.24",
30
30
  "@reventlessdev/rescript-pulumi-pulumi": "3.0.0-alpha.0",
31
- "@reventlessdev/rescript-web": "1.0.0-alpha.8",
32
31
  "@reventlessdev/rescript-uuid": "2.0.0-alpha.1",
33
- "@reventlessdev/reventless-core": "3.0.0-alpha.316",
32
+ "@reventlessdev/rescript-web": "1.0.0-alpha.8",
33
+ "@reventlessdev/reventless-core": "3.0.0-alpha.317",
34
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.214",
34
35
  "@reventlessdev/reventless-interop": "3.0.0-alpha.42",
35
- "@reventlessdev/reventless-spec": "3.0.0-alpha.184",
36
- "@reventlessdev/reventless-infra": "3.0.0-alpha.213",
37
- "@reventlessdev/reventless-postgres": "3.0.0-alpha.180"
36
+ "@reventlessdev/reventless-postgres": "3.0.0-alpha.181",
37
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.185"
38
38
  },
39
39
  "devDependencies": {
40
40
  "rescript": "12.3.1",
@@ -71,11 +71,29 @@ type registeredHandler = {
71
71
  plugin?: string,
72
72
  }
73
73
 
74
+ // Each Lambda keeps its own key cache, so an event naming a key fetches it here,
75
+ // before the handler decodes it; an event naming none passes straight through.
76
+ let withPreparedKeys = (
77
+ handleJsonEvents: ReventlessCore.EventCollector.jsonEventsHandler,
78
+ ): ReventlessCore.EventCollector.jsonEventsHandler =>
79
+ stream =>
80
+ stream
81
+ ->Stream.mapEffect(json =>
82
+ Reventless.Pii.needsPrepare([json])
83
+ ? Effect.promise(() => Reventless.Pii.prepareOrThrow([json]))->Effect.map(_ => json)
84
+ : Effect.succeed(json)
85
+ )
86
+ ->handleJsonEvents
87
+
74
88
  let toStreamHandler = (
75
89
  handleJsonEvents: ReventlessCore.EventCollector.jsonEventsHandler,
76
90
  ): streamHandler =>
77
91
  (event, context) =>
78
- EventCollectorChannel_DynamoDbStream_Runtime.handleStreamEvent(handleJsonEvents, event, context)
92
+ EventCollectorChannel_DynamoDbStream_Runtime.handleStreamEvent(
93
+ withPreparedKeys(handleJsonEvents),
94
+ event,
95
+ context,
96
+ )
79
97
 
80
98
  // Multiple components can share one source stream — e.g. every admin read
81
99
  // model (Plugins, PluginHistory, PlatformEventGraph, UIFragmentRegistry)
@@ -2,6 +2,9 @@
2
2
 
3
3
  import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
4
4
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Stream from "effect/Stream";
7
+ import * as Pii$Reventless from "@reventlessdev/reventless-spec/src/components/Pii.res.mjs";
5
8
  import * as HandlerFactoryHelpersMjs from "./HandlerFactoryHelpers.mjs";
6
9
  import * as EventCollectorChannel_DynamoDbStream_Runtime$ReventlessAws from "../EventCollector/EventCollectorChannel_DynamoDbStream_Runtime.res.mjs";
7
10
 
@@ -41,8 +44,18 @@ function exnMessage(exn) {
41
44
  return Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "unknown error");
42
45
  }
43
46
 
47
+ function withPreparedKeys(handleJsonEvents) {
48
+ return stream => handleJsonEvents(Stream.mapEffect(stream, json => {
49
+ if (Pii$Reventless.needsPrepare([json])) {
50
+ return Effect.map(Effect.promise(() => Pii$Reventless.prepareOrThrow([json])), () => json);
51
+ } else {
52
+ return Effect.succeed(json);
53
+ }
54
+ }));
55
+ }
56
+
44
57
  function toStreamHandler(handleJsonEvents) {
45
- return (event, context) => EventCollectorChannel_DynamoDbStream_Runtime$ReventlessAws.handleStreamEvent(handleJsonEvents, event, context);
58
+ return (event, context) => EventCollectorChannel_DynamoDbStream_Runtime$ReventlessAws.handleStreamEvent(withPreparedKeys(handleJsonEvents), event, context);
46
59
  }
47
60
 
48
61
  function addToRegistry(registry, sourceUrn, handler) {
@@ -115,6 +128,7 @@ export {
115
128
  logWarn,
116
129
  logError,
117
130
  exnMessage,
131
+ withPreparedKeys,
118
132
  toStreamHandler,
119
133
  addToRegistry,
120
134
  groupBySource,
@@ -0,0 +1,51 @@
1
+ // A Lambda's stream handler fetches the keys an event's sealed fields name before
2
+ // the component decodes it, and asks for nothing when an event names none.
3
+
4
+ open JestGlobals
5
+
6
+ let asked: ref<array<array<string>>> = ref([])
7
+ let provider: Reventless.Pii.provider = {
8
+ ...Reventless.Pii.plain,
9
+ name: "counting",
10
+ prefetch: async keyIds => {
11
+ asked := asked.contents->Array.concat([keyIds])
12
+ Ok()
13
+ },
14
+ }
15
+
16
+ let sealed =
17
+ Dict.fromArray([
18
+ (
19
+ "event",
20
+ Dict.fromArray([
21
+ ("TAG", JSON.Encode.string("MemberNamed")),
22
+ ("name", Reventless.Pii.wrap("enc:v1:k-7:fake:AAAA")),
23
+ ])->JSON.Encode.object,
24
+ ),
25
+ ])->JSON.Encode.object
26
+
27
+ describe("StreamRoutedEntryPoint_Ops.withPreparedKeys", () => {
28
+ beforeEach(() => {
29
+ asked := []
30
+ Reventless.Pii.Provider.install(provider)
31
+ })
32
+ afterEach(() => Reventless.Pii.Provider.install(Reventless.Pii.plain))
33
+
34
+ testPromise("prefetches before the handler sees the event, and only what it names", async () => {
35
+ let seen = ref([])
36
+ let handler: ReventlessCore.EventCollector.jsonEventsHandler = stream =>
37
+ stream->Stream.runForEach(
38
+ json =>
39
+ Effect.sync(
40
+ () => seen := seen.contents->Array.concat([(json, asked.contents->Array.length)]),
41
+ ),
42
+ )
43
+ let wrapped = StreamRoutedEntryPoint_Ops.withPreparedKeys(handler)
44
+ let _ = await wrapped(
45
+ Stream.fromIterable([sealed, JSON.Encode.string("plain")]),
46
+ )->Effect.runPromise
47
+ expect(asked.contents)->toEqual([["k-7"]])
48
+ // The sealed event arrived after its key was asked for.
49
+ expect(seen.contents->Array.map(((_, n)) => n))->toEqual([1, 1])
50
+ })
51
+ })