@reventlessdev/reventless-core 3.0.0-alpha.174 → 3.0.0-alpha.176

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.
Files changed (88) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/package.json +7 -7
  3. package/src/ComponentType.res +4 -4
  4. package/src/ComponentType.res.mjs +6 -6
  5. package/src/RequestContext.res +45 -1
  6. package/src/RequestContext.res.mjs +12 -2
  7. package/src/ResourceAttribution.res +133 -0
  8. package/src/ResourceAttribution.res.mjs +96 -0
  9. package/src/adapter/Runtime/AggregateRuntime_Builder_Common.res +24 -5
  10. package/src/adapter/Runtime/AggregateRuntime_Builder_Common.res.mjs +9 -3
  11. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +6 -0
  12. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res.mjs +3 -3
  13. package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res +6 -1
  14. package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res.mjs +3 -1
  15. package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +25 -7
  16. package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res.mjs +11 -8
  17. package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res +2 -0
  18. package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res.mjs +1 -1
  19. package/src/adapter/Runtime/PluginRuntime_Builder_Micro.res +4 -0
  20. package/src/adapter/Runtime/PluginRuntime_Builder_Micro.res.mjs +2 -2
  21. package/src/adapter/Runtime/PluginRuntime_Builder_Single.res +4 -0
  22. package/src/adapter/Runtime/PluginRuntime_Builder_Single.res.mjs +2 -2
  23. package/src/adapter/Runtime/Runtime.res +49 -10
  24. package/src/adapter/Runtime/Runtime.res.mjs +22 -8
  25. package/src/admin/Platform_Admin.res +1 -1
  26. package/src/admin/Platform_Admin.res.mjs +8 -2
  27. package/src/components/Aggregate/Aggregate_Builder.res +10 -2
  28. package/src/components/Aggregate/Aggregate_Builder.res.mjs +8 -2
  29. package/src/components/AutomationSlice/AutomationSlice_Builder.res +12 -2
  30. package/src/components/AutomationSlice/AutomationSlice_Builder.res.mjs +8 -2
  31. package/src/components/CommandTopic/CommandTopic.res +5 -1
  32. package/src/components/CommandTopic/CommandTopic_Adapter.res +1 -0
  33. package/src/components/CommandTopic/CommandTopic_Builder.res +4 -4
  34. package/src/components/CommandTopic/CommandTopic_Builder.res.mjs +29 -30
  35. package/src/components/Counter/Counter_Builder.res +7 -1
  36. package/src/components/Counter/Counter_Builder.res.mjs +5 -2
  37. package/src/components/Dcb/Dcb_Builder.res +2 -2
  38. package/src/components/Dcb/Dcb_Builder.res.mjs +8 -2
  39. package/src/components/DcbEventLog/DcbEventLog_Builder.res +3 -0
  40. package/src/components/DcbEventLog/DcbEventLog_Builder.res.mjs +4 -1
  41. package/src/components/EventCollector/EventCollector.res +1 -0
  42. package/src/components/EventCollector/EventCollector_Adapter.res +1 -0
  43. package/src/components/EventCollector/EventCollector_Builder.res +4 -4
  44. package/src/components/EventCollector/EventCollector_Builder.res.mjs +2 -2
  45. package/src/components/EventLog/EventLog.res +5 -1
  46. package/src/components/EventLog/EventLog_Adapter.res +5 -1
  47. package/src/components/EventLog/EventLog_Builder.res +9 -4
  48. package/src/components/EventLog/EventLog_Builder.res.mjs +7 -8
  49. package/src/components/EventMapper/EventMapper_Builder.res +6 -1
  50. package/src/components/EventMapper/EventMapper_Builder.res.mjs +4 -1
  51. package/src/components/EventTopic/EventTopic.res +1 -0
  52. package/src/components/EventTopic/EventTopic_Adapter.res +1 -0
  53. package/src/components/EventTopic/EventTopic_Builder.res +4 -3
  54. package/src/components/EventTopic/EventTopic_Builder.res.mjs +2 -2
  55. package/src/components/ExtensionPoint/ExtensionPoint_Builder.res +11 -2
  56. package/src/components/ExtensionPoint/ExtensionPoint_Builder.res.mjs +8 -2
  57. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Builder.res +6 -1
  58. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Builder.res.mjs +4 -1
  59. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res +12 -2
  60. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res.mjs +8 -2
  61. package/src/components/QueryDb/QueryDb.res +1 -0
  62. package/src/components/QueryDb/QueryDb_Adapter.res +1 -0
  63. package/src/components/QueryDb/QueryDb_Builder.res +4 -3
  64. package/src/components/QueryDb/QueryDb_Builder.res.mjs +2 -2
  65. package/src/components/ReadModel/ReadModel_Builder.res +12 -2
  66. package/src/components/ReadModel/ReadModel_Builder.res.mjs +8 -2
  67. package/src/components/SideEffectHandler/SideEffectHandler_Builder.res +6 -1
  68. package/src/components/SideEffectHandler/SideEffectHandler_Builder.res.mjs +4 -1
  69. package/src/components/StateViewSlice/StateViewSlice_Builder.res +12 -2
  70. package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +8 -2
  71. package/src/plugin/component/Plugin_Builder.res +8 -2
  72. package/src/plugin/component/Plugin_Builder.res.mjs +4 -1
  73. package/src/plugin/component/Plugin_Helpers.res +1 -1
  74. package/src/plugin/component/Plugin_Helpers.res.mjs +4 -1
  75. package/src/plugin/connect/PluginExtensionPoint_Plugin.res +26 -12
  76. package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +8 -8
  77. package/src/util/Interstack.res +1 -1
  78. package/src/util/Interstack.res.mjs +3 -3
  79. package/src/util/Interstack.resi +1 -1
  80. package/src/util/Util_StackRefs.res +2 -2
  81. package/src/util/Util_StackRefs.res.mjs +4 -4
  82. package/tests/ResourceAttributionTest.res +70 -0
  83. package/tests/aggregate/AggregateCacheTest.res +1 -1
  84. package/tests/aggregate/AggregateConflictTest.res +1 -1
  85. package/tests/aggregate/AggregateFixtures.res +1 -1
  86. package/tests/aggregate/AggregateSnapshotTest.res +1 -1
  87. package/tests/eventlog/EventLogFixtures.res +1 -1
  88. package/tests/logger/LogFormatTest.res +43 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,33 @@
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.176 (2026-07-22)
7
+
8
+ * refactor!: retire the stale "core" vocabulary for platform things ([34e7480](https://github.com/ReventlessDev/reventless-core/commit/34e7480992bd58906a250b0a1ce6ff2c5ba45260))
9
+
10
+ ### BREAKING CHANGES
11
+
12
+ * the built-in extension point is renamed Core.Plugin ->
13
+ Platform.Plugin. This replaces the CorePluginExtPointCmdTopic SQS queue
14
+ with PlatformPluginExtPointCmdTopic (a replacement, not an update) and
15
+ breaks every already-deployed plugin's connection until redeployed.
16
+ Wipe the alpha stack and redeploy fresh rather than migrating.
17
+
18
+ Build clean; 1349 tests green (interop 50, core 518, local 501, aws 280).
19
+
20
+
21
+
22
+ # 3.0.0-alpha.175 (2026-07-22)
23
+
24
+ ### Features
25
+
26
+ * **aws:** give deployed resources a complete attribution tag schema ([f931a44](https://github.com/ReventlessDev/reventless-core/commit/f931a44ab311a4aff1cd73939b42e7e5221621c9))
27
+ * **aws:** unify the deployed entry-point dispatch boundary; add latency fields ([ad7b3f6](https://github.com/ReventlessDev/reventless-core/commit/ad7b3f60e7b2b2213677732bbf13f486043075ef))
28
+ * **core:** annotate event-collector logs with the element's comp ([eda413a](https://github.com/ReventlessDev/reventless-core/commit/eda413ab00eb8bb02b30e029af2d6221e3e9ba75)), closes [#1](https://github.com/ReventlessDev/reventless-core/issues/1)
29
+ * **core:** attribute piece resources to the component that owns them ([2ddd91a](https://github.com/ReventlessDev/reventless-core/commit/2ddd91ae1a5394257dec4b9b6e5021d5aa6e7f63))
30
+ * **core:** attribute shared substrate to the plugin that owns it ([a440d4f](https://github.com/ReventlessDev/reventless-core/commit/a440d4f827dfab9e2e9a763ffd9fc40240852e09))
31
+
32
+
6
33
  # 3.0.0-alpha.174 (2026-07-21)
7
34
 
8
35
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-core",
3
- "version": "3.0.0-alpha.174",
3
+ "version": "3.0.0-alpha.176",
4
4
  "description": "Core package for Reventless framework",
5
5
  "license": "Apache-2.0",
6
6
  "jest": {
@@ -28,17 +28,17 @@
28
28
  "dependencies": {
29
29
  "sury": "11.0.0-alpha.4",
30
30
  "uuid": "^13.0.0",
31
- "@reventlessdev/rescript-hash-object": "1.2.0-alpha.13",
31
+ "@reventlessdev/rescript-effect": "0.1.0-alpha.30",
32
32
  "@reventlessdev/rescript-fast-csv": "1.2.0-alpha.14",
33
33
  "@reventlessdev/rescript-jest": "1.0.0-alpha.9",
34
+ "@reventlessdev/rescript-hash-object": "1.2.0-alpha.13",
34
35
  "@reventlessdev/rescript-node-streams": "1.1.0-alpha.13",
35
- "@reventlessdev/rescript-effect": "0.1.0-alpha.29",
36
36
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.17",
37
37
  "@reventlessdev/rescript-ssh2": "1.1.0-alpha.14",
38
- "@reventlessdev/rescript-uuid": "1.1.0-alpha.17",
39
- "@reventlessdev/reventless-infra": "3.0.0-alpha.102",
40
- "@reventlessdev/reventless-interop": "3.0.0-alpha.28",
41
- "@reventlessdev/reventless-spec": "3.0.0-alpha.79"
38
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.104",
39
+ "@reventlessdev/reventless-interop": "3.0.0-alpha.29",
40
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.80",
41
+ "@reventlessdev/rescript-uuid": "1.1.0-alpha.17"
42
42
  },
43
43
  "devDependencies": {
44
44
  "rescript": "12.3.0",
@@ -2,6 +2,7 @@ type t =
2
2
  | Aggregate
3
3
  | Counter
4
4
  | Plugin
5
+ | Platform
5
6
  | CommandGenerator
6
7
  | CommandTopic
7
8
  | EventCollector
@@ -17,7 +18,6 @@ type t =
17
18
  | SideEffectHandler
18
19
  | Task
19
20
  | Vpc
20
- | Core
21
21
  | Heartbeat
22
22
  | Cloner
23
23
  | DcbEventLog
@@ -32,6 +32,7 @@ let toString = componentType =>
32
32
  | Aggregate => "Aggregate"
33
33
  | Counter => "Counter"
34
34
  | Plugin => "Plugin"
35
+ | Platform => "Platform"
35
36
  | CommandGenerator => "CommandGenerator"
36
37
  | CommandTopic => "CommandTopic"
37
38
  | EventCollector => "EventCollector"
@@ -47,7 +48,6 @@ let toString = componentType =>
47
48
  | SideEffectHandler => "SideEffectHandler"
48
49
  | Task => "Task"
49
50
  | Vpc => "Vpc"
50
- | Core => "Core"
51
51
  | Heartbeat => "Heartbeat"
52
52
  | Cloner => "Cloner"
53
53
  | DcbEventLog => "DcbEventLog"
@@ -63,6 +63,7 @@ let ofString = str =>
63
63
  | "Aggregate" => Aggregate->Some
64
64
  | "Counter" => Counter->Some
65
65
  | "Plugin" => Plugin->Some
66
+ | "Platform" => Platform->Some
66
67
  | "CommandGenerator" => CommandGenerator->Some
67
68
  | "CommandTopic" => CommandTopic->Some
68
69
  | "EventCollector" => EventCollector->Some
@@ -78,7 +79,6 @@ let ofString = str =>
78
79
  | "SideEffectHandler" => SideEffectHandler->Some
79
80
  | "Task" => Task->Some
80
81
  | "Vpc" => Vpc->Some
81
- | "Core" => Core->Some
82
82
  | "Heartbeat" => Heartbeat->Some
83
83
  | "Cloner" => Cloner->Some
84
84
  | "DcbEventLog" => DcbEventLog->Some
@@ -95,6 +95,7 @@ let toName = componentType =>
95
95
  | Aggregate => "Aggr"
96
96
  | Counter => "Counter"
97
97
  | Plugin => "Plugin"
98
+ | Platform => "Platform"
98
99
  | CommandGenerator => "CmdGen"
99
100
  | CommandTopic => "CmdTopic"
100
101
  | EventCollector => "EventColl"
@@ -110,7 +111,6 @@ let toName = componentType =>
110
111
  | SideEffectHandler => "SideEffectHandler"
111
112
  | Task => "Task"
112
113
  | Vpc => "Vpc"
113
- | Core => "Core"
114
114
  | Heartbeat => "Heartbeat"
115
115
  | Cloner => "Cloner"
116
116
  | DcbEventLog => "DcbEventLog"
@@ -10,6 +10,8 @@ function toString(componentType) {
10
10
  return "Counter";
11
11
  case "Plugin" :
12
12
  return "Plugin";
13
+ case "Platform" :
14
+ return "Platform";
13
15
  case "CommandGenerator" :
14
16
  return "CommandGenerator";
15
17
  case "CommandTopic" :
@@ -40,8 +42,6 @@ function toString(componentType) {
40
42
  return "Task";
41
43
  case "Vpc" :
42
44
  return "Vpc";
43
- case "Core" :
44
- return "Core";
45
45
  case "Heartbeat" :
46
46
  return "Heartbeat";
47
47
  case "Cloner" :
@@ -73,8 +73,6 @@ function ofString(str) {
73
73
  return "CommandGenerator";
74
74
  case "CommandTopic" :
75
75
  return "CommandTopic";
76
- case "Core" :
77
- return "Core";
78
76
  case "Counter" :
79
77
  return "Counter";
80
78
  case "DcbEventLog" :
@@ -97,6 +95,8 @@ function ofString(str) {
97
95
  return "InboundTranslationSlice";
98
96
  case "OutboundTranslationSlice" :
99
97
  return "OutboundTranslationSlice";
98
+ case "Platform" :
99
+ return "Platform";
100
100
  case "Plugin" :
101
101
  return "Plugin";
102
102
  case "QueryDB" :
@@ -130,6 +130,8 @@ function toName(componentType) {
130
130
  return "Counter";
131
131
  case "Plugin" :
132
132
  return "Plugin";
133
+ case "Platform" :
134
+ return "Platform";
133
135
  case "CommandGenerator" :
134
136
  return "CmdGen";
135
137
  case "CommandTopic" :
@@ -160,8 +162,6 @@ function toName(componentType) {
160
162
  return "Task";
161
163
  case "Vpc" :
162
164
  return "Vpc";
163
- case "Core" :
164
- return "Core";
165
165
  case "Heartbeat" :
166
166
  return "Heartbeat";
167
167
  case "Cloner" :
@@ -19,13 +19,24 @@
19
19
  // causal chain within one `correlationId`. `component` / `pluginName` identify the
20
20
  // component and plugin handling the invocation — mirror the `comp` / `plugin` log
21
21
  // fields so a consumer of this service sees the same attribution the logs carry.
22
- // All three are optional: absent in `.test()` and wherever the dispatch site has
22
+ //
23
+ // `timestamp` = when the triggering message was *sent* (ms since epoch), not when
24
+ // this handler started: SQS `SentTimestamp`, a DynamoDB stream record's
25
+ // `ApproximateCreationDateTime`, or dispatch time in-process. A handler computes
26
+ // end-to-end latency from it without calling `Date.now()` itself, and the value
27
+ // includes queue dwell — which a handler-local clock cannot see.
28
+ // `retryCount` = delivery attempt, 1 on first delivery (SQS
29
+ // `ApproximateReceiveCount`; always 1 where the transport has no redelivery).
30
+ //
31
+ // All optional fields are absent in `.test()` and wherever the dispatch site has
23
32
  // no value to supply.
24
33
  type t = {
25
34
  correlationId: string,
26
35
  causationId?: string,
27
36
  component?: string,
28
37
  pluginName?: string,
38
+ timestamp?: float,
39
+ retryCount?: int,
29
40
  identity: Reventless.Identity.t,
30
41
  claims: dict<string>,
31
42
  }
@@ -39,6 +50,8 @@ let make = (
39
50
  ~causationId=?,
40
51
  ~component=?,
41
52
  ~pluginName=?,
53
+ ~timestamp=?,
54
+ ~retryCount=?,
42
55
  ~identity=Reventless.Identity.anonymous,
43
56
  ~claims=Dict.make(),
44
57
  ): t => {
@@ -46,10 +59,37 @@ let make = (
46
59
  causationId: ?causationId,
47
60
  component: ?component,
48
61
  pluginName: ?pluginName,
62
+ timestamp: ?timestamp,
63
+ retryCount: ?retryCount,
49
64
  identity,
50
65
  claims,
51
66
  }
52
67
 
68
+ // JS-facing constructor for the hand-written Lambda entry-point shells
69
+ // (HandlerFactoryHelpers.mjs). `make`'s labelled arguments compile to *positional*
70
+ // ones, so a JS caller breaks silently the moment an argument is inserted; this
71
+ // takes a single options object whose field names survive compilation and stay
72
+ // compiler-checked here. Every field is optional so a shell can supply only what
73
+ // its transport actually carries.
74
+ type options = {
75
+ correlationId?: string,
76
+ causationId?: string,
77
+ component?: string,
78
+ pluginName?: string,
79
+ timestamp?: float,
80
+ retryCount?: int,
81
+ }
82
+
83
+ let fromOptions = (o: options): t =>
84
+ make(
85
+ ~correlationId=o.correlationId->Option.getOr("unknown"),
86
+ ~causationId=?o.causationId,
87
+ ~component=?o.component,
88
+ ~pluginName=?o.pluginName,
89
+ ~timestamp=?o.timestamp,
90
+ ~retryCount=?o.retryCount,
91
+ )
92
+
53
93
  let getClaim = (ctx: t, key: string): option<string> =>
54
94
  ctx.claims->Dict.get(key)
55
95
 
@@ -61,10 +101,14 @@ let withClaim = (ctx: t, key: string, value: string): t => {
61
101
 
62
102
  let test = (
63
103
  ~correlationId="test-correlation-id",
104
+ ~timestamp=?,
105
+ ~retryCount=?,
64
106
  ~identity=Reventless.Identity.anonymous,
65
107
  ~claims=Dict.make(),
66
108
  ): t => {
67
109
  correlationId,
110
+ timestamp: ?timestamp,
111
+ retryCount: ?retryCount,
68
112
  identity,
69
113
  claims,
70
114
  }
@@ -1,11 +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 Context from "effect/Context";
4
5
  import * as Identity$Reventless from "@reventlessdev/reventless-spec/src/types/Identity.res.mjs";
5
6
 
6
7
  let tag = Context.GenericTag("reventless/RequestContext");
7
8
 
8
- function make(correlationId, causationId, component, pluginName, identityOpt, claimsOpt) {
9
+ function make(correlationId, causationId, component, pluginName, timestamp, retryCount, identityOpt, claimsOpt) {
9
10
  let identity = identityOpt !== undefined ? identityOpt : Identity$Reventless.anonymous;
10
11
  let claims = claimsOpt !== undefined ? claimsOpt : ({});
11
12
  return {
@@ -13,11 +14,17 @@ function make(correlationId, causationId, component, pluginName, identityOpt, cl
13
14
  causationId: causationId,
14
15
  component: component,
15
16
  pluginName: pluginName,
17
+ timestamp: timestamp,
18
+ retryCount: retryCount,
16
19
  identity: identity,
17
20
  claims: claims
18
21
  };
19
22
  }
20
23
 
24
+ function fromOptions(o) {
25
+ return make(Stdlib_Option.getOr(o.correlationId, "unknown"), o.causationId, o.component, o.pluginName, o.timestamp, o.retryCount, undefined, undefined);
26
+ }
27
+
21
28
  function getClaim(ctx, key) {
22
29
  return ctx.claims[key];
23
30
  }
@@ -30,12 +37,14 @@ function withClaim(ctx, key, value) {
30
37
  return newrecord;
31
38
  }
32
39
 
33
- function test(correlationIdOpt, identityOpt, claimsOpt) {
40
+ function test(correlationIdOpt, timestamp, retryCount, identityOpt, claimsOpt) {
34
41
  let correlationId = correlationIdOpt !== undefined ? correlationIdOpt : "test-correlation-id";
35
42
  let identity = identityOpt !== undefined ? identityOpt : Identity$Reventless.anonymous;
36
43
  let claims = claimsOpt !== undefined ? claimsOpt : ({});
37
44
  return {
38
45
  correlationId: correlationId,
46
+ timestamp: timestamp,
47
+ retryCount: retryCount,
39
48
  identity: identity,
40
49
  claims: claims
41
50
  };
@@ -44,6 +53,7 @@ function test(correlationIdOpt, identityOpt, claimsOpt) {
44
53
  export {
45
54
  tag,
46
55
  make,
56
+ fromOptions,
47
57
  getClaim,
48
58
  withClaim,
49
59
  test,
@@ -0,0 +1,133 @@
1
+ /***
2
+ The vocabulary a deployed resource is attributed with: which model element owns
3
+ it, in what role, at what level. Provider-agnostic on purpose — AWS renders these
4
+ as namespaced `reventless:` tags, Kubernetes as `reventless.io` labels. Defining
5
+ them once here is what keeps the two backends (and the monitoring registry) from
6
+ drifting into private spellings of the same fact.
7
+
8
+ The three facts are deliberately independent:
9
+
10
+ - `ComponentType.t` — the *modelling* kind (Aggregate, StateViewSlice, …): what
11
+ the element IS in the domain model.
12
+ - `Role.t` — the *deployment piece* (EventLog, QueryDb, Runtime, …): what job
13
+ this particular resource does for that element. One component owns several
14
+ pieces, so kind alone can't identify a resource.
15
+ - `Scope.t` — the level the resource is attributed to: an individual component,
16
+ a plugin's shared substrate, or platform substrate.
17
+
18
+ Note this is NOT the same axis as `Monitoring.unitKind`, which classifies an
19
+ execution unit by what its *failure* means (CommandHandler / Projection /
20
+ Reactor). A `Runtime` role can be any of those; both facts are worth carrying and
21
+ neither derives from the other.
22
+ */
23
+
24
+ /** The level a resource is attributed to. */
25
+ module Scope = {
26
+ type t =
27
+ | /** owned by one model component */ Component
28
+ | /** shared substrate within a plugin (DcbEventLog, plugin DLQ, …) */ Plugin
29
+ | /** shared substrate across the platform (API, auth, hosting, …) */ Platform
30
+
31
+ let toString = scope =>
32
+ switch scope {
33
+ | Component => "component"
34
+ | Plugin => "plugin"
35
+ | Platform => "platform"
36
+ }
37
+ }
38
+
39
+ /**
40
+ The deployment piece a resource implements. `Other(string)` is the escape hatch
41
+ for support pieces and future roles (same pattern as `Monitoring.unitKind`).
42
+ */
43
+ module Role = {
44
+ type t =
45
+ | CommandTopic
46
+ | EventTopic
47
+ | StateTopic
48
+ | EventLog
49
+ | DcbEventLog
50
+ | EventLogSubscription
51
+ | EventCollector
52
+ | QueryDb
53
+ | /** the execution unit that runs a component's handler */ Runtime
54
+ | /** queue/topic receiving messages that exhausted processing */ DeadLetter
55
+ | /** scheduled invocation (heartbeat, task scheduler) */ Scheduler
56
+ | /** log storage and log-derived metrics */ Logs
57
+ | /** execution identity and its policies */ Identity
58
+ | /** the GraphQL API surface and its resolvers */ Api
59
+ | /** identity provider / user pools */ Auth
60
+ | /** static-site hosting, CDN, certificates, DNS */ Hosting
61
+ | /** VPC and its network plumbing */ Network
62
+ | /** transport wiring between a source and a runtime */ EventSourceMapping
63
+ | /** bulk data movement (cloner, migrations) */ DataTransfer
64
+ | Other(string)
65
+
66
+ let toString = role =>
67
+ switch role {
68
+ | CommandTopic => "CommandTopic"
69
+ | EventTopic => "EventTopic"
70
+ | StateTopic => "StateTopic"
71
+ | EventLog => "EventLog"
72
+ | DcbEventLog => "DcbEventLog"
73
+ | EventLogSubscription => "EventLogSubscription"
74
+ | EventCollector => "EventCollector"
75
+ | QueryDb => "QueryDb"
76
+ | Runtime => "Runtime"
77
+ | DeadLetter => "DeadLetter"
78
+ | Scheduler => "Scheduler"
79
+ | Logs => "Logs"
80
+ | Identity => "Identity"
81
+ | Api => "Api"
82
+ | Auth => "Auth"
83
+ | Hosting => "Hosting"
84
+ | Network => "Network"
85
+ | EventSourceMapping => "EventSourceMapping"
86
+ | DataTransfer => "DataTransfer"
87
+ | Other(name) => name
88
+ }
89
+ }
90
+
91
+ /**
92
+ The model component a provisioned resource belongs to.
93
+
94
+ Piece builders (EventLog, QueryDb, CommandTopic, EventTopic, EventCollector) are
95
+ shared building blocks applied as functors by many different component kinds — a
96
+ QueryDb is instantiated by ReadModel, StateViewSlice, AutomationSlice, both
97
+ translation slices and Counter. The adapter that provisions the physical resource
98
+ sits at the bottom of that chain and would otherwise only know its own piece, so
99
+ `kind` would collapse onto `role` and the owning component would be unrecoverable.
100
+ The owning builder passes this record down instead.
101
+
102
+ `name` is the owner's spec name (the component stem, `Products`), not the
103
+ suffixed resource name (`ProductsQueryDb`).
104
+ */
105
+ type owner = {kind: ComponentType.t, name: string}
106
+
107
+ /**
108
+ Ambient deploy-time context: which plugin (and platform) is currently being
109
+ constructed. Adapters that create resources sit far below the builder that knows
110
+ these names, and threading two strings through every adapter signature would be a
111
+ large, purely mechanical churn — so the plugin builder publishes them here for
112
+ the duration of its construct, exactly as it already does for
113
+ `Logger.currentPluginName`.
114
+
115
+ Safe because deploy-time resource construction is synchronous (the framework
116
+ forbids creating resources inside `Pulumi.Output.apply`), so everything built
117
+ between `enter` and `restore` genuinely belongs to that plugin. Outside any
118
+ plugin construct both are `None` — which is the correct answer for
119
+ platform-scope substrate.
120
+ */
121
+ type context = {platform: option<string>, plugin: option<string>}
122
+
123
+ let current: ref<context> = ref({platform: None, plugin: None})
124
+
125
+ /** Publish the plugin being constructed; returns the previous context to restore. */
126
+ let enter = (~platform: string, ~plugin: string) => {
127
+ let previous = current.contents
128
+ current := {platform: Some(platform), plugin: Some(plugin)}
129
+ previous
130
+ }
131
+
132
+ /** Restore the context captured by `enter`. */
133
+ let restore = (previous: context) => current := previous
@@ -0,0 +1,96 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+
4
+ function toString(scope) {
5
+ switch (scope) {
6
+ case "Component" :
7
+ return "component";
8
+ case "Plugin" :
9
+ return "plugin";
10
+ case "Platform" :
11
+ return "platform";
12
+ }
13
+ }
14
+
15
+ let Scope = {
16
+ toString: toString
17
+ };
18
+
19
+ function toString$1(role) {
20
+ if (typeof role === "object") {
21
+ return role._0;
22
+ }
23
+ switch (role) {
24
+ case "CommandTopic" :
25
+ return "CommandTopic";
26
+ case "EventTopic" :
27
+ return "EventTopic";
28
+ case "StateTopic" :
29
+ return "StateTopic";
30
+ case "EventLog" :
31
+ return "EventLog";
32
+ case "DcbEventLog" :
33
+ return "DcbEventLog";
34
+ case "EventLogSubscription" :
35
+ return "EventLogSubscription";
36
+ case "EventCollector" :
37
+ return "EventCollector";
38
+ case "QueryDb" :
39
+ return "QueryDb";
40
+ case "Runtime" :
41
+ return "Runtime";
42
+ case "DeadLetter" :
43
+ return "DeadLetter";
44
+ case "Scheduler" :
45
+ return "Scheduler";
46
+ case "Logs" :
47
+ return "Logs";
48
+ case "Identity" :
49
+ return "Identity";
50
+ case "Api" :
51
+ return "Api";
52
+ case "Auth" :
53
+ return "Auth";
54
+ case "Hosting" :
55
+ return "Hosting";
56
+ case "Network" :
57
+ return "Network";
58
+ case "EventSourceMapping" :
59
+ return "EventSourceMapping";
60
+ case "DataTransfer" :
61
+ return "DataTransfer";
62
+ }
63
+ }
64
+
65
+ let Role = {
66
+ toString: toString$1
67
+ };
68
+
69
+ let current = {
70
+ contents: {
71
+ platform: undefined,
72
+ plugin: undefined
73
+ }
74
+ };
75
+
76
+ function enter(platform, plugin) {
77
+ let previous = current.contents;
78
+ current.contents = {
79
+ platform: platform,
80
+ plugin: plugin
81
+ };
82
+ return previous;
83
+ }
84
+
85
+ function restore(previous) {
86
+ current.contents = previous;
87
+ }
88
+
89
+ export {
90
+ Scope,
91
+ Role,
92
+ current,
93
+ enter,
94
+ restore,
95
+ }
96
+ /* No side effect */
@@ -26,20 +26,29 @@ module Make = (
26
26
  }
27
27
  type effectHandler = Runtime.effectHandler<RuntimeEnvironment.event, context, unit, string>
28
28
 
29
+ // Event collectors nested under this aggregate belong to their own element (a
30
+ // ReadModel, an EventMapper, …), so they carry the comp resolved at registration
31
+ // time rather than the hosting aggregate's.
32
+ type registeredHandler = {comp: string, handler: effectHandler}
33
+
29
34
  let runtimeSpecs: dict<runtimeSpec> = Dict.make()
30
35
  let commandGeneratorHandlers: dict<CommandGenerator.effectEventHandler<context>> = Dict.make()
31
36
  let commandTopicHandlers: dict<effectHandler> = Dict.make()
32
- let eventCollectorHandlers: dict<array<effectHandler>> = Dict.make()
37
+ let eventCollectorHandlers: dict<array<registeredHandler>> = Dict.make()
33
38
 
34
39
  let aggregateHandler = aggregateName =>
35
40
  async (event: RuntimeEnvironment.event, context) => {
36
41
  let correlationId = event->RuntimeEnvironment.extractCorrelationId
37
42
  let causationId = event->RuntimeEnvironment.extractCausationId
43
+ let timestamp = event->RuntimeEnvironment.extractSentTimestamp
44
+ let retryCount = event->RuntimeEnvironment.extractRetryCount
38
45
  let comp = `AggregateRuntime(${aggregateName})`
39
46
  // Shared dispatch helper (Runtime.runEffect) annotates correlationId / comp /
40
47
  // causationId onto the invocation so the application handler's own log lines
41
- // carry them without re-logging by hand.
42
- let runEffect = effect => Runtime.runEffect(~correlationId?, ~causationId?, ~comp, effect)
48
+ // carry them without re-logging by hand, and carries the transport's send
49
+ // time / delivery attempt into RequestContext.
50
+ let runEffect = effect =>
51
+ Runtime.runEffect(~correlationId?, ~causationId?, ~comp, ~timestamp?, ~retryCount?, effect)
43
52
  switch event->CommandGenerator.metaInfo {
44
53
  | Some(info) =>
45
54
  switch commandGeneratorHandlers->Dict.get(info) {
@@ -71,7 +80,16 @@ module Make = (
71
80
  `found ${count} EventCollector handler(s) for ${urn}`,
72
81
  )->Effect.runSync
73
82
  let _ = await handlers
74
- ->Array.map(handler => runEffect(handler(event, context)))
83
+ ->Array.map(({comp, handler}) =>
84
+ Runtime.runEffect(
85
+ ~correlationId?,
86
+ ~causationId?,
87
+ ~comp,
88
+ ~timestamp?,
89
+ ~retryCount?,
90
+ handler(event, context),
91
+ )
92
+ )
75
93
  ->Promise.all
76
94
  | None =>
77
95
  let available =
@@ -237,11 +255,12 @@ module Make = (
237
255
  ~comp="AggregateRuntime",
238
256
  `forEventCollector ${eventCollectorName}: set handler for ${urns->Array.join(", ")}`,
239
257
  )
258
+ let comp = `EventCollector(${eventCollectorName})`
240
259
  urns->Array.map(urn => {
241
260
  let handlers = eventCollectorHandlers->Dict.get(urn)->Option.getOr([])
242
261
  eventCollectorHandlers->Dict.set(
243
262
  urn,
244
- handlers->Array.concat([handler->RuntimeEnvironment.asEffectHandler]),
263
+ handlers->Array.concat([{comp, handler: handler->RuntimeEnvironment.asEffectHandler}]),
245
264
  )
246
265
  })
247
266
  })
@@ -21,8 +21,10 @@ function Make(RuntimeEnvironment) {
21
21
  let aggregateHandler = aggregateName => (async (event, context) => {
22
22
  let correlationId = RuntimeEnvironment.extractCorrelationId(event);
23
23
  let causationId = RuntimeEnvironment.extractCausationId(event);
24
+ let timestamp = RuntimeEnvironment.extractSentTimestamp(event);
25
+ let retryCount = RuntimeEnvironment.extractRetryCount(event);
24
26
  let comp = `AggregateRuntime(` + aggregateName + `)`;
25
- let runEffect = effect => Runtime$ReventlessCore.runEffect(correlationId, causationId, comp, undefined, undefined, undefined, effect);
27
+ let runEffect = effect => Runtime$ReventlessCore.runEffect(correlationId, causationId, comp, undefined, timestamp, retryCount, undefined, undefined, effect);
26
28
  let info = CommandGenerator$ReventlessCore.metaInfo(event);
27
29
  if (info !== undefined) {
28
30
  let handler = commandGeneratorHandlers[info];
@@ -46,7 +48,7 @@ function Make(RuntimeEnvironment) {
46
48
  if (handlers !== undefined) {
47
49
  let count = handlers.length.toString();
48
50
  Effect.runSync(EffectLogger$ReventlessCore.logDebug(comp, undefined, `found ` + count + ` EventCollector handler(s) for ` + urn));
49
- await Promise.all(handlers.map(handler => runEffect(handler(event, context))));
51
+ await Promise.all(handlers.map(param => Runtime$ReventlessCore.runEffect(correlationId, causationId, param.comp, undefined, timestamp, retryCount, undefined, undefined, param.handler(event, context))));
50
52
  return;
51
53
  }
52
54
  let available = Object.keys(commandTopicHandlers).concat(Object.keys(eventCollectorHandlers)).join(",");
@@ -155,9 +157,13 @@ function Make(RuntimeEnvironment) {
155
157
  let handler = param[1];
156
158
  let urns = param[0];
157
159
  log.debug("AggregateRuntime", undefined, `forEventCollector ` + eventCollectorName + `: set handler for ` + urns.join(", "));
160
+ let comp = `EventCollector(` + eventCollectorName + `)`;
158
161
  return urns.map(urn => {
159
162
  let handlers = Stdlib_Option.getOr(eventCollectorHandlers[urn], []);
160
- eventCollectorHandlers[urn] = handlers.concat([RuntimeEnvironment.asEffectHandler(handler)]);
163
+ eventCollectorHandlers[urn] = handlers.concat([{
164
+ comp: comp,
165
+ handler: RuntimeEnvironment.asEffectHandler(handler)
166
+ }]);
161
167
  });
162
168
  });
163
169
  };
@@ -32,6 +32,8 @@ module Make = (
32
32
  ->Runtime.runEffectHandler(
33
33
  ~extractCorrelationId=RuntimeEnvironment.extractCorrelationId,
34
34
  ~extractCausationId=RuntimeEnvironment.extractCausationId,
35
+ ~extractSentTimestamp=RuntimeEnvironment.extractSentTimestamp,
36
+ ~extractRetryCount=RuntimeEnvironment.extractRetryCount,
35
37
  ~comp=name,
36
38
  )
37
39
  ),
@@ -60,6 +62,8 @@ module Make = (
60
62
  ->Runtime.runEffectHandler(
61
63
  ~extractCorrelationId=RuntimeEnvironment.extractCorrelationId,
62
64
  ~extractCausationId=RuntimeEnvironment.extractCausationId,
65
+ ~extractSentTimestamp=RuntimeEnvironment.extractSentTimestamp,
66
+ ~extractRetryCount=RuntimeEnvironment.extractRetryCount,
63
67
  ~comp=name,
64
68
  )
65
69
  ),
@@ -91,6 +95,8 @@ module Make = (
91
95
  ->Runtime.runEffectHandler(
92
96
  ~extractCorrelationId=RuntimeEnvironment.extractCorrelationId,
93
97
  ~extractCausationId=RuntimeEnvironment.extractCausationId,
98
+ ~extractSentTimestamp=RuntimeEnvironment.extractSentTimestamp,
99
+ ~extractRetryCount=RuntimeEnvironment.extractRetryCount,
94
100
  ~comp=name,
95
101
  )
96
102
  ),