@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
@@ -58,7 +58,12 @@ module Make = (
58
58
  let timeout = ReventlessInfra.RuntimeHints.resolveTimeout(runtime, ~default=30)
59
59
 
60
60
  module SpecificQueryDb = QueryDb_Builder.Make(Spec, QueryDbStorage, QueryDbResolvers)
61
- let queryDb = SpecificQueryDb.make(~api, ~apiRole, ~opts)
61
+ let queryDb = SpecificQueryDb.make(
62
+ ~api,
63
+ ~apiRole,
64
+ ~owner={kind: ComponentType.ReadModel, name: Spec.name},
65
+ ~opts,
66
+ )
62
67
 
63
68
  let toProjectionOperations: SpecificQueryDb.operations => projectionOperations = ({
64
69
  load,
@@ -114,7 +119,12 @@ module Make = (
114
119
  ->Component.operations
115
120
  ->Pulumi.Output.apply(operations => {
116
121
  let eventTopics = allEventTopics->EventTopic.filter(sourceNames)
117
- let eventCollector = SpecificEventCollector.make(~name, ~eventTopics, ~opts)
122
+ let eventCollector = SpecificEventCollector.make(
123
+ ~name,
124
+ ~eventTopics,
125
+ ~owner={kind: ComponentType.ReadModel, name: Spec.name},
126
+ ~opts,
127
+ )
118
128
 
119
129
  module Callback = ReadModel_Callback.Make(
120
130
  Spec,
@@ -27,7 +27,10 @@ function Make(Spec) {
27
27
  let memorySize = RuntimeHints$ReventlessInfra.resolveMemory(runtime, 1024);
28
28
  let timeout = RuntimeHints$ReventlessInfra.resolveTimeout(runtime, 30);
29
29
  let SpecificQueryDb = QueryDb_Builder$ReventlessCore.Make(Spec)(QueryDbStorage)(QueryDbResolvers);
30
- let queryDb = SpecificQueryDb.make(api, apiRole, undefined, opts);
30
+ let queryDb = SpecificQueryDb.make(api, apiRole, undefined, {
31
+ kind: "ReadModel",
32
+ name: Spec.name
33
+ }, opts);
31
34
  let toProjectionOperations = param => {
32
35
  let deleteBatch = param.deleteBatch;
33
36
  let $$delete = param.delete;
@@ -64,7 +67,10 @@ function Make(Spec) {
64
67
  let SpecificEventCollector = EventCollector_Builder$ReventlessCore.Make(RuntimeEnvironment)(EventCollectorChannel);
65
68
  let eventCollector = Component$ReventlessCore.operations(queryDb).apply(operations => {
66
69
  let eventTopics = EventTopic$ReventlessCore.filter(allEventTopics, sourceNames);
67
- let eventCollector = SpecificEventCollector.make(name, eventTopics, opts);
70
+ let eventCollector = SpecificEventCollector.make(name, eventTopics, {
71
+ kind: "ReadModel",
72
+ name: Spec.name
73
+ }, opts);
68
74
  let operations$1 = toProjectionOperations(operations);
69
75
  let Callback = ReadModel_Callback$ReventlessCore.Make(Spec)(Mappings)({
70
76
  ReadModelSpec: Spec,
@@ -27,7 +27,12 @@ module Make = (
27
27
  ->Belt.Set.String.fromArray
28
28
 
29
29
  let eventTopics = allEventTopics->EventTopic.filter(aggregateNames)
30
- let eventCollector = SpecificEventCollector.make(~name, ~eventTopics, ~opts)
30
+ let eventCollector = SpecificEventCollector.make(
31
+ ~name,
32
+ ~eventTopics,
33
+ ~owner={kind: ComponentType.SideEffectHandler, name},
34
+ ~opts,
35
+ )
31
36
 
32
37
  module Callback = SideEffectHandler_Callback.Make({
33
38
  let sideEffects = sideEffects
@@ -24,7 +24,10 @@ function Make(RuntimeEnvironment) {
24
24
  };
25
25
  let aggregateNames = Belt_SetString.fromArray(sideEffects.map(SideEffect => SideEffect.Source.name));
26
26
  let eventTopics = EventTopic$ReventlessCore.filter(allEventTopics, aggregateNames);
27
- let eventCollector = SpecificEventCollector.make(extra$1, eventTopics, opts);
27
+ let eventCollector = SpecificEventCollector.make(extra$1, eventTopics, {
28
+ kind: "SideEffectHandler",
29
+ name: extra$1
30
+ }, opts);
28
31
  let Callback = SideEffectHandler_Callback$ReventlessCore.Make({
29
32
  sideEffects: sideEffects,
30
33
  queryEngine: queryEngine
@@ -63,7 +63,12 @@ module Make = (
63
63
  let memorySize = ReventlessInfra.RuntimeHints.resolveMemory(runtime, ~default=1024)
64
64
  let timeout = ReventlessInfra.RuntimeHints.resolveTimeout(runtime, ~default=30)
65
65
 
66
- let queryDb = SpecificQueryDb.make(~api=Api.api(), ~apiRole=Api.apiRole(), ~opts)
66
+ let queryDb = SpecificQueryDb.make(
67
+ ~api=Api.api(),
68
+ ~apiRole=Api.apiRole(),
69
+ ~owner={kind: ComponentType.StateViewSlice, name: Spec.name},
70
+ ~opts,
71
+ )
67
72
 
68
73
  let dcbEventTopicOutputs: EventTopic.outputs = (dcbEventLog->Component.outputs).eventTopic
69
74
  let allEventTopics = Dict.fromArray([(Spec.name, dcbEventTopicOutputs)])
@@ -74,7 +79,12 @@ module Make = (
74
79
  ->Pulumi.Output.apply(queryDbOps => {
75
80
  let projectionOps = toProjectionOps(queryDbOps)
76
81
 
77
- let ec = SpecificEventCollector.make(~name=Spec.name, ~eventTopics=allEventTopics, ~opts)
82
+ let ec = SpecificEventCollector.make(
83
+ ~name=Spec.name,
84
+ ~eventTopics=allEventTopics,
85
+ ~owner={kind: ComponentType.StateViewSlice, name: Spec.name},
86
+ ~opts,
87
+ )
78
88
 
79
89
  let comp = `StateViewSlice(${Spec.name})`
80
90
 
@@ -61,7 +61,10 @@ function Make(RuntimeEnvironment) {
61
61
  };
62
62
  let memorySize = RuntimeHints$ReventlessInfra.resolveMemory(runtime, 1024);
63
63
  let timeout = RuntimeHints$ReventlessInfra.resolveTimeout(runtime, 30);
64
- let queryDb = SpecificQueryDb.make(Api.api(), Api.apiRole(), undefined, opts);
64
+ let queryDb = SpecificQueryDb.make(Api.api(), Api.apiRole(), undefined, {
65
+ kind: "StateViewSlice",
66
+ name: Spec.name
67
+ }, opts);
65
68
  let dcbEventTopicOutputs = Component$ReventlessCore.outputs(dcbEventLog).eventTopic;
66
69
  let allEventTopics = Object.fromEntries([[
67
70
  Spec.name,
@@ -69,7 +72,10 @@ function Make(RuntimeEnvironment) {
69
72
  ]]);
70
73
  let eventCollector = Component$ReventlessCore.operations(queryDb).apply(queryDbOps => {
71
74
  let projectionOps = toProjectionOps(queryDbOps);
72
- let ec = SpecificEventCollector.make(Spec.name, allEventTopics, opts);
75
+ let ec = SpecificEventCollector.make(Spec.name, allEventTopics, {
76
+ kind: "StateViewSlice",
77
+ name: Spec.name
78
+ }, opts);
73
79
  let comp = `StateViewSlice(` + Spec.name + `)`;
74
80
  let jsonEventsHandler = stream => Effect.flatMap(Stream.runCollect(stream), events => {
75
81
  let total = events.length.toString();
@@ -67,6 +67,11 @@ module Make = (
67
67
  let _prevPluginName = Logger.currentPluginName.contents
68
68
  Logger.currentPluginName := Some(name)
69
69
 
70
+ // Publish the owning plugin/platform for resource attribution, so adapters
71
+ // creating infrastructure below this point can tag it without every adapter
72
+ // signature having to carry the two names. Restored at the end of construct.
73
+ let _prevAttribution = ResourceAttribution.enter(~platform=Spec.platformName, ~plugin=name)
74
+
70
75
  // Register every component → plugin so runtime logs (fired after construct
71
76
  // returns) can resolve a comp like `StateChangeSlice(AddProduct)` to its
72
77
  // owning plugin via `Logger.componentPluginRegistry`. Also register the
@@ -570,8 +575,8 @@ module Make = (
570
575
  let builderOutputs = {
571
576
  // Resolve admin extension point data — from Interstack (AWS cross-stack reference).
572
577
  let interstackAdminExtensionPoints =
573
- Interstack.coreStackReference->Option.mapOr(Pulumi.Output.make(None), coreStack =>
574
- coreStack->Pulumi.StackReference.getOutput("extensionPoints")
578
+ Interstack.platformStackReference->Option.mapOr(Pulumi.Output.make(None), platformStack =>
579
+ platformStack->Pulumi.StackReference.getOutput("extensionPoints")
575
580
  )
576
581
 
577
582
  // Derive local admin extension point resolved data (passed from makePlatform).
@@ -975,6 +980,7 @@ module Make = (
975
980
  )
976
981
 
977
982
  Logger.currentPluginName := _prevPluginName
983
+ ResourceAttribution.restore(_prevAttribution)
978
984
  }
979
985
 
980
986
  let makeAutoUIManifest = (
@@ -31,6 +31,7 @@ import * as AdapterDeploytime$ReventlessCore from "../../adapter/AdapterDeployti
31
31
  import * as ExtensionMapping$ReventlessInfra from "@reventlessdev/reventless-infra/src/types/ExtensionMapping.res.mjs";
32
32
  import * as ExtensionPoint$ReventlessInterop from "@reventlessdev/reventless-interop/src/components/ExtensionPoint.res.mjs";
33
33
  import * as Heartbeat_Builder$ReventlessCore from "../../components/Heartbeat/Heartbeat_Builder.res.mjs";
34
+ import * as ResourceAttribution$ReventlessCore from "../../ResourceAttribution.res.mjs";
34
35
  import * as PluginExtensionPointSpec$ReventlessInfra from "@reventlessdev/reventless-infra/src/types/PluginExtensionPointSpec.res.mjs";
35
36
  import * as Plugin_SubscriptionSchema$ReventlessCore from "./Plugin_SubscriptionSchema.res.mjs";
36
37
 
@@ -121,6 +122,7 @@ function Make(Spec) {
121
122
  return Component$ReventlessCore.make(ComponentType$ReventlessCore.toString(Plugin$ReventlessCore.componentType), name, (extra, extra$1) => {
122
123
  let _prevPluginName = Logger$ReventlessCore.currentPluginName.contents;
123
124
  Logger$ReventlessCore.currentPluginName.contents = extra$1;
125
+ let _prevAttribution = ResourceAttribution$ReventlessCore.enter(Spec.platformName, extra$1);
124
126
  Logger$ReventlessCore.registerComponentPlugin(extra$1, extra$1);
125
127
  aggregates.forEach(M => Logger$ReventlessCore.registerComponentPlugin(M.Spec.name, extra$1));
126
128
  readModels.forEach(R => Logger$ReventlessCore.registerComponentPlugin(R.Spec.name, extra$1));
@@ -397,7 +399,7 @@ function Make(Spec) {
397
399
  components: components
398
400
  });
399
401
  }
400
- let interstackAdminExtensionPoints = Stdlib_Option.mapOr(Interstack$ReventlessCore.coreStackReference, Pulumi.output(undefined), coreStack => coreStack.getOutput("extensionPoints"));
402
+ let interstackAdminExtensionPoints = Stdlib_Option.mapOr(Interstack$ReventlessCore.platformStackReference, Pulumi.output(undefined), platformStack => platformStack.getOutput("extensionPoints"));
401
403
  let localAdminResolvedEP = Output$Pulumi.flatMap(Spec.hooks.adminExtensionPoints.contents, eps => {
402
404
  let ep = eps[PluginExtensionPointSpec$ReventlessInfra.name];
403
405
  if (ep !== undefined) {
@@ -626,6 +628,7 @@ function Make(Spec) {
626
628
  Component$ReventlessCore.setOutputs(extra, pluginOutputs);
627
629
  Plugin_Helpers$ReventlessCore.interopMetaOutput.contents = builderOutputs.apply(outputs => S.reverseConvertToJsonOrThrow(Plugin_Helpers$ReventlessCore.toInteropMeta(outputs), ExportMeta$ReventlessInterop.schema));
628
630
  Logger$ReventlessCore.currentPluginName.contents = _prevPluginName;
631
+ return ResourceAttribution$ReventlessCore.restore(_prevAttribution);
629
632
  }, opts);
630
633
  };
631
634
  return {
@@ -449,7 +449,7 @@ module MakeEventCollectorHelper = (
449
449
  EventCollectorChannel,
450
450
  )
451
451
  let make = (~name, ~eventTopics, ~opts) => {
452
- let eventCollector = PluginEventCollector.make(~name, ~eventTopics, ~opts)
452
+ let eventCollector = PluginEventCollector.make(~name, ~eventTopics, ~owner={kind: ComponentType.Plugin, name}, ~opts)
453
453
  let eventCollectorOutputs = eventCollector->Component.outputs
454
454
  // pluginDefinition.eventCollector must identify the EC's inbound queue
455
455
  // ARN — admin's `manageSubscriptions` uses it as the subscription target
@@ -255,7 +255,10 @@ function MakeEventCollectorHelper(RuntimeEnvironment) {
255
255
  return EventCollectorChannel => (PluginRuntimeBuilder => {
256
256
  let PluginEventCollector = EventCollector_Builder$ReventlessCore.Make(RuntimeEnvironment)(EventCollectorChannel);
257
257
  let make = (name, eventTopics, opts) => {
258
- let eventCollector = PluginEventCollector.make(name, eventTopics, opts);
258
+ let eventCollector = PluginEventCollector.make(name, eventTopics, {
259
+ kind: "Plugin",
260
+ name: name
261
+ }, opts);
259
262
  let eventCollectorOutputs = Component$ReventlessCore.outputs(eventCollector);
260
263
  let resources = eventCollectorOutputs.resources;
261
264
  let r = resources[resources.length - 1 | 0];
@@ -47,7 +47,7 @@ module Make = (Spec: Spec) => {
47
47
  switch jsons {
48
48
  | [] =>
49
49
  EffectLogger.logWarn(
50
- ~comp="Core.Plugin",
50
+ ~comp=PluginExtensionPointSpec.name,
51
51
  `ForwardCommand: Couldn't find Plugin with ExtensionPoint ${extensionPointName}`,
52
52
  )->Effect.runSync
53
53
  | plugins =>
@@ -66,28 +66,31 @@ module Make = (Spec: Spec) => {
66
66
  ) {
67
67
  | _ =>
68
68
  EffectLogger.logInfo(
69
- ~comp="Core.Plugin",
69
+ ~comp=PluginExtensionPointSpec.name,
70
70
  `ForwardCommand: published command to ${plugin.name} ${extensionPoint.commandTopic}`,
71
71
  )->Effect.runSync
72
72
  | exception err =>
73
73
  let errMsg =
74
74
  err->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown")
75
75
  EffectLogger.logError(
76
- ~comp="Core.Plugin",
76
+ ~comp=PluginExtensionPointSpec.name,
77
77
  `ForwardCommand: Error on publish command: ${errMsg}`,
78
78
  )->Effect.runSync
79
79
  }
80
80
 
81
81
  | None =>
82
82
  EffectLogger.logWarn(
83
- ~comp="Core.Plugin",
83
+ ~comp=PluginExtensionPointSpec.name,
84
84
  `ForwardCommand: Couldn't find ExtensionPoint ${extensionPointName} in ${plugin.name}`,
85
85
  )->Effect.runSync
86
86
  }
87
87
  | exception err =>
88
88
  let errMsg =
89
89
  err->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown")
90
- EffectLogger.logError(~comp="Core.Plugin", `ForwardCommand: Couldn't decode Plugin: ${errMsg}`)->Effect.runSync
90
+ EffectLogger.logError(
91
+ ~comp=PluginExtensionPointSpec.name,
92
+ `ForwardCommand: Couldn't decode Plugin: ${errMsg}`,
93
+ )->Effect.runSync
91
94
  }
92
95
  }
93
96
  }
@@ -105,7 +108,7 @@ module Make = (Spec: Spec) => {
105
108
  rate: timeout->ScheduleOps.minutesFromNow,
106
109
  payload: {
107
110
  Message.id,
108
- meta: Message.generateMeta(~service="Core.Plugin", ~user="Scheduler"),
111
+ meta: Message.generateMeta(~service=PluginExtensionPointSpec.name, ~user="Scheduler"),
109
112
  command: PluginExtensionPointSpec.DisconnectPlugin,
110
113
  }
111
114
  ->Message.encodeCommand'(S.string, PluginExtensionPointSpec.commandSchema)
@@ -155,7 +158,10 @@ module Make = (Spec: Spec) => {
155
158
  PublishCommand(Plugin.name(id), Delegate.Heartbeat(Plugin.version(id))),
156
159
  // Re-arm the disconnect schedule with an interval-scaled grace so a
157
160
  // single late beat doesn't trip a spurious disconnect (see disconnectGrace).
158
- HandleDirective(directiveHandler, CreateDisconnectSchedule(id, disconnectGrace(interval))),
161
+ HandleDirective(
162
+ directiveHandler,
163
+ CreateDisconnectSchedule(id, disconnectGrace(interval)),
164
+ ),
159
165
  ]
160
166
  | RedetectPlugin(interval) => [
161
167
  // Deploy-time re-detect: drive Redetect (not Heartbeat) so an already-connected
@@ -163,7 +169,10 @@ module Make = (Spec: Spec) => {
163
169
  // re-arm the disconnect schedule exactly like a heartbeat so liveness tracking
164
170
  // continues from the deploy moment.
165
171
  PublishCommand(Plugin.name(id), Delegate.Redetect(Plugin.version(id))),
166
- HandleDirective(directiveHandler, CreateDisconnectSchedule(id, disconnectGrace(interval))),
172
+ HandleDirective(
173
+ directiveHandler,
174
+ CreateDisconnectSchedule(id, disconnectGrace(interval)),
175
+ ),
167
176
  ]
168
177
  | ConnectPlugin(pluginDefinition) =>
169
178
  // Validate protocol versions declared by the connecting plugin.
@@ -172,7 +181,7 @@ module Make = (Spec: Spec) => {
172
181
  let protocolErrors =
173
182
  pluginDefinition.extensionProtocols->Array.flatMap(proto =>
174
183
  ReventlessInterop.Compat.validateProtocol(
175
- ~host=ReventlessInterop.CompatMatrix.corePlugin,
184
+ ~host=ReventlessInterop.CompatMatrix.platformPlugin,
176
185
  ~extensionPointName=proto.extensionPointName,
177
186
  ~commandVersion=proto.commandVersion,
178
187
  ~eventVersion=proto.eventVersion,
@@ -180,7 +189,7 @@ module Make = (Spec: Spec) => {
180
189
  )
181
190
  let reportAction = if protocolErrors->Array.length > 0 {
182
191
  EffectLogger.logWarn(
183
- ~comp="Core.Plugin",
192
+ ~comp=PluginExtensionPointSpec.name,
184
193
  `Protocol version mismatch for plugin ${pluginDefinition.id}: ${protocolErrors
185
194
  ->JSON.stringifyAny
186
195
  ->Option.getOr("[]")}`,
@@ -197,7 +206,9 @@ module Make = (Spec: Spec) => {
197
206
  PublishCommand(Plugin.name(id), Delegate.Disconnect(Plugin.version(id))),
198
207
  HandleDirective(directiveHandler, DeleteDisconnectSchedule(id)),
199
208
  ]
200
- | ForwardCommand(forwardCommand) => [HandleDirective(directiveHandler, ForwardCommand(forwardCommand))]
209
+ | ForwardCommand(forwardCommand) => [
210
+ HandleDirective(directiveHandler, ForwardCommand(forwardCommand)),
211
+ ]
201
212
  // Routed to the UiFragmentRegistry slice by the sibling UI-fragment mapping, not the
202
213
  // Plugin aggregate — a no-op here.
203
214
  | RegisterUiFragment(_) => []
@@ -212,7 +223,10 @@ module Make = (Spec: Spec) => {
212
223
  // definition publish with `def.id` (= name@version), preserving the prior
213
224
  // cross-plugin wire id.
214
225
  | Delegate.VersionDetected(version) => [
215
- PublishEvent(Plugin.makeId(id, version), PluginExtensionPointSpec.UnknownPluginDetected),
226
+ PublishEvent(
227
+ Plugin.makeId(id, version),
228
+ PluginExtensionPointSpec.UnknownPluginDetected,
229
+ ),
216
230
  ]
217
231
  | VersionConnected(pluginDefinition)
218
232
  | VersionPromoted(pluginDefinition) => [
@@ -43,7 +43,7 @@ function Make(Spec) {
43
43
  ]
44
44
  ], 1000);
45
45
  if (jsons.length === 0) {
46
- return Effect.runSync(EffectLogger$ReventlessCore.logWarn("Core.Plugin", undefined, `ForwardCommand: Couldn't find Plugin with ExtensionPoint ` + extensionPointName));
46
+ return Effect.runSync(EffectLogger$ReventlessCore.logWarn(PluginExtensionPointSpec$ReventlessInfra.name, undefined, `ForwardCommand: Couldn't find Plugin with ExtensionPoint ` + extensionPointName));
47
47
  }
48
48
  let plugin = jsons[0];
49
49
  let exit = 0;
@@ -54,12 +54,12 @@ function Make(Spec) {
54
54
  } catch (raw_err) {
55
55
  let err = Primitive_exceptions.internalToException(raw_err);
56
56
  let errMsg = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(err), Stdlib_JsExn.message), "unknown");
57
- return Effect.runSync(EffectLogger$ReventlessCore.logError("Core.Plugin", undefined, `ForwardCommand: Couldn't decode Plugin: ` + errMsg));
57
+ return Effect.runSync(EffectLogger$ReventlessCore.logError(PluginExtensionPointSpec$ReventlessInfra.name, undefined, `ForwardCommand: Couldn't decode Plugin: ` + errMsg));
58
58
  }
59
59
  if (exit === 1) {
60
60
  let extensionPoint = plugin$1.extensionPoints.find(extensionPoint => extensionPoint.name === extensionPointName);
61
61
  if (extensionPoint === undefined) {
62
- return Effect.runSync(EffectLogger$ReventlessCore.logWarn("Core.Plugin", undefined, `ForwardCommand: Couldn't find ExtensionPoint ` + extensionPointName + ` in ` + plugin$1.name));
62
+ return Effect.runSync(EffectLogger$ReventlessCore.logWarn(PluginExtensionPointSpec$ReventlessInfra.name, undefined, `ForwardCommand: Couldn't find ExtensionPoint ` + extensionPointName + ` in ` + plugin$1.name));
63
63
  }
64
64
  let exit$1 = 0;
65
65
  let val;
@@ -69,10 +69,10 @@ function Make(Spec) {
69
69
  } catch (raw_err$1) {
70
70
  let err$1 = Primitive_exceptions.internalToException(raw_err$1);
71
71
  let errMsg$1 = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(err$1), Stdlib_JsExn.message), "unknown");
72
- return Effect.runSync(EffectLogger$ReventlessCore.logError("Core.Plugin", undefined, `ForwardCommand: Error on publish command: ` + errMsg$1));
72
+ return Effect.runSync(EffectLogger$ReventlessCore.logError(PluginExtensionPointSpec$ReventlessInfra.name, undefined, `ForwardCommand: Error on publish command: ` + errMsg$1));
73
73
  }
74
74
  if (exit$1 === 2) {
75
- return Effect.runSync(EffectLogger$ReventlessCore.logInfo("Core.Plugin", undefined, `ForwardCommand: published command to ` + plugin$1.name + ` ` + extensionPoint.commandTopic));
75
+ return Effect.runSync(EffectLogger$ReventlessCore.logInfo(PluginExtensionPointSpec$ReventlessInfra.name, undefined, `ForwardCommand: published command to ` + plugin$1.name + ` ` + extensionPoint.commandTopic));
76
76
  }
77
77
  }
78
78
  };
@@ -85,7 +85,7 @@ function Make(Spec) {
85
85
  rate: ScheduleOps$ReventlessCore.minutesFromNow(directive._1),
86
86
  payload: JSON.stringify(Message$ReventlessCore.encodeCommand$p({
87
87
  id: id,
88
- meta: Message$ReventlessCore.generateMeta("Core.Plugin", undefined, "Scheduler", undefined, undefined, undefined, undefined, undefined),
88
+ meta: Message$ReventlessCore.generateMeta(PluginExtensionPointSpec$ReventlessInfra.name, undefined, "Scheduler", undefined, undefined, undefined, undefined, undefined),
89
89
  command: "DisconnectPlugin"
90
90
  }, S.string, PluginExtensionPointSpec$ReventlessInfra.commandSchema))
91
91
  });
@@ -162,8 +162,8 @@ function Make(Spec) {
162
162
  ];
163
163
  case "ConnectPlugin" :
164
164
  let pluginDefinition = cmd._0;
165
- let protocolErrors = pluginDefinition.extensionProtocols.flatMap(proto => Compat$ReventlessInterop.validateProtocol(CompatMatrix$ReventlessInterop.corePlugin, proto.extensionPointName, proto.commandVersion, proto.eventVersion));
166
- let reportAction = protocolErrors.length !== 0 ? (Effect.runSync(EffectLogger$ReventlessCore.logWarn("Core.Plugin", undefined, `Protocol version mismatch for plugin ` + pluginDefinition.id + `: ` + Stdlib_Option.getOr(JSON.stringify(protocolErrors), "[]"))), [{
165
+ let protocolErrors = pluginDefinition.extensionProtocols.flatMap(proto => Compat$ReventlessInterop.validateProtocol(CompatMatrix$ReventlessInterop.platformPlugin, proto.extensionPointName, proto.commandVersion, proto.eventVersion));
166
+ let reportAction = protocolErrors.length !== 0 ? (Effect.runSync(EffectLogger$ReventlessCore.logWarn(PluginExtensionPointSpec$ReventlessInfra.name, undefined, `Protocol version mismatch for plugin ` + pluginDefinition.id + `: ` + Stdlib_Option.getOr(JSON.stringify(protocolErrors), "[]"))), [{
167
167
  TAG: "PublishCommand",
168
168
  _0: Plugin$ReventlessCore.name(id),
169
169
  _1: {
@@ -1,4 +1,4 @@
1
- let coreStackReference =
1
+ let platformStackReference =
2
2
  Pulumi.Config.make(Some("platform"))
3
3
  ->Pulumi.Config.get("stack")
4
4
  ->Option.map(stack =>
@@ -10,7 +10,7 @@ import * as Query$ReventlessInterop from "@reventlessdev/reventless-interop/src/
10
10
  import * as EventMapper$ReventlessInterop from "@reventlessdev/reventless-interop/src/components/EventMapper.res.mjs";
11
11
  import * as ExtensionPoint$ReventlessInterop from "@reventlessdev/reventless-interop/src/components/ExtensionPoint.res.mjs";
12
12
 
13
- let coreStackReference = Stdlib_Option.map(new Pulumi.Config("platform").get("stack"), stack => new Pulumi.StackReference(stack + "-interstack", {
13
+ let platformStackReference = Stdlib_Option.map(new Pulumi.Config("platform").get("stack"), stack => new Pulumi.StackReference(stack + "-interstack", {
14
14
  name: stack
15
15
  }));
16
16
 
@@ -115,7 +115,7 @@ let mergeEventMappers = DefaultEventMapperQuery.mergeWith;
115
115
  let mergeExtensionPoints = DefaultExtensionPointQuery.mergeWith;
116
116
 
117
117
  export {
118
- coreStackReference,
118
+ platformStackReference,
119
119
  stackDependenciesTasks,
120
120
  stackDependenciesEventMappers,
121
121
  stackDependenciesExtensionPoints,
@@ -123,4 +123,4 @@ export {
123
123
  mergeEventMappers,
124
124
  mergeExtensionPoints,
125
125
  }
126
- /* coreStackReference Not a pure module */
126
+ /* platformStackReference Not a pure module */
@@ -1,4 +1,4 @@
1
- let coreStackReference: option<Pulumi.StackReference.t>
1
+ let platformStackReference: option<Pulumi.StackReference.t>
2
2
 
3
3
  let stackDependenciesTasks: Pulumi.Output.t<
4
4
  array<result<ReventlessInterop.Task.resolvedOutputs, ReventlessInterop.Compat.error>>,
@@ -1,9 +1,9 @@
1
1
  let stackRefs: dict<Pulumi.StackReference.t> = Dict.make()
2
2
 
3
- let coreStackName = Pulumi.Config.make(Some("platform"))->Pulumi.Config.get("stack")
3
+ let platformStackName = Pulumi.Config.make(Some("platform"))->Pulumi.Config.get("stack")
4
4
 
5
5
  let stackName = pluginName =>
6
- coreStackName->Option.map(name => {
6
+ platformStackName->Option.map(name => {
7
7
  let parts = name->String.split("/")
8
8
  parts->Array.set(1, pluginName)
9
9
  parts->Array.joinUnsafe("/")
@@ -6,10 +6,10 @@ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js
6
6
 
7
7
  let stackRefs = {};
8
8
 
9
- let coreStackName = new Pulumi.Config("platform").get("stack");
9
+ let platformStackName = new Pulumi.Config("platform").get("stack");
10
10
 
11
11
  function stackName(pluginName) {
12
- return Stdlib_Option.map(coreStackName, name => {
12
+ return Stdlib_Option.map(platformStackName, name => {
13
13
  let parts = name.split("/");
14
14
  parts[1] = pluginName;
15
15
  return parts.join("/");
@@ -32,8 +32,8 @@ function get(pluginName) {
32
32
 
33
33
  export {
34
34
  stackRefs,
35
- coreStackName,
35
+ platformStackName,
36
36
  stackName,
37
37
  get,
38
38
  }
39
- /* coreStackName Not a pure module */
39
+ /* platformStackName Not a pure module */
@@ -0,0 +1,70 @@
1
+ open JestGlobals
2
+
3
+ // The attribution vocabulary is the shared contract between the AWS tag renderer
4
+ // and the Kubernetes label renderer. These guard the wire spellings (which land
5
+ // in deployed resource metadata and in downstream inventories) and the ambient
6
+ // context's save/restore discipline, which is what keeps a plugin's resources
7
+ // from being attributed to whichever plugin was constructed before it.
8
+
9
+ module Attribution = ResourceAttribution
10
+
11
+ describe("ResourceAttribution.Scope — wire spellings", () => {
12
+ testSync("scopes render lower-case", () => {
13
+ expect(
14
+ [Attribution.Scope.Component, Plugin, Platform]->Array.map(Attribution.Scope.toString),
15
+ )->toEqual(["component", "plugin", "platform"])
16
+ })
17
+ })
18
+
19
+ describe("ResourceAttribution.Role — wire spellings", () => {
20
+ testSync("piece roles render as their constructor name", () => {
21
+ expect(
22
+ [Attribution.Role.EventLog, QueryDb, Runtime, DeadLetter]->Array.map(
23
+ Attribution.Role.toString,
24
+ ),
25
+ )->toEqual(["EventLog", "QueryDb", "Runtime", "DeadLetter"])
26
+ })
27
+
28
+ testSync("Other carries the caller's name verbatim", () => {
29
+ expect(Attribution.Role.Other("ChangeFeed")->Attribution.Role.toString)->toBe("ChangeFeed")
30
+ })
31
+
32
+ testSync("platform-level things are Platform, not Core", () => {
33
+ // `Core` predates the platform/plugin split and names nothing the framework
34
+ // builds; it also reads as the built-in core PLUGIN, which is a different
35
+ // thing. Platform substrate is attributed to `Platform`, matching
36
+ // `reventless:platform` and `Scope.Platform`.
37
+ expect(ComponentType.Platform->ComponentType.toString)->toBe("Platform")
38
+ expect(ComponentType.ofString("Platform"))->toEqual(Some(ComponentType.Platform))
39
+ })
40
+
41
+ testSync("a role is NOT a component kind — Runtime has no ComponentType twin", () => {
42
+ // The whole point of splitting role from kind: `Runtime` is a deployment
43
+ // piece, not something the domain model can be. If this ever resolves, the
44
+ // two vocabularies have started to merge again.
45
+ expect(ComponentType.ofString("Runtime"))->toEqual(None)
46
+ })
47
+ })
48
+
49
+ describe("ResourceAttribution — ambient plugin context", () => {
50
+ testSync("outside any plugin construct, nothing is attributed", () => {
51
+ expect(Attribution.current.contents.plugin)->toEqual(None)
52
+ expect(Attribution.current.contents.platform)->toEqual(None)
53
+ })
54
+
55
+ testSync("enter publishes the plugin and platform under construction", () => {
56
+ let previous = Attribution.enter(~platform="online-shop", ~plugin="Ordering")
57
+ expect(Attribution.current.contents.plugin)->toEqual(Some("Ordering"))
58
+ expect(Attribution.current.contents.platform)->toEqual(Some("online-shop"))
59
+ Attribution.restore(previous)
60
+ })
61
+
62
+ testSync("restore unwinds to the previous context, so plugins don't leak", () => {
63
+ let outer = Attribution.enter(~platform="online-shop", ~plugin="Catalog")
64
+ let inner = Attribution.enter(~platform="online-shop", ~plugin="Ordering")
65
+ Attribution.restore(inner)
66
+ expect(Attribution.current.contents.plugin)->toEqual(Some("Catalog"))
67
+ Attribution.restore(outer)
68
+ expect(Attribution.current.contents.plugin)->toEqual(None)
69
+ })
70
+ })
@@ -166,7 +166,7 @@ module TestOps = {
166
166
  }
167
167
  type component = Component.t<OuterEventLog.t, OuterEventLog.outputs, operations>
168
168
  // Never called — satisfies module type only
169
- let make = (~name as _: string, ~opts as _=?): component => Obj.magic(0)
169
+ let make = (~name as _: string, ~owner as _=?, ~opts as _=?): component => Obj.magic(0)
170
170
  }
171
171
  let eventLog: EventLog.operations = {
172
172
  append: mock.appendFn,
@@ -126,7 +126,7 @@ module TestOps = {
126
126
  writeSnapshot: (string, EventLog.snapshot) => promise<result<unit, string>>,
127
127
  }
128
128
  type component = Component.t<OuterEventLog.t, OuterEventLog.outputs, operations>
129
- let make = (~name as _: string, ~opts as _=?): component => Obj.magic(0)
129
+ let make = (~name as _: string, ~owner as _=?, ~opts as _=?): component => Obj.magic(0)
130
130
  }
131
131
  let eventLog: EventLog.operations = {
132
132
  append: mock.appendFn,
@@ -142,7 +142,7 @@ module TestOps = {
142
142
  }
143
143
  type component = Component.t<OuterEventLog.t, OuterEventLog.outputs, operations>
144
144
  // Never called — satisfies module type only
145
- let make = (~name as _: string, ~opts as _=?): component => Obj.magic(0)
145
+ let make = (~name as _: string, ~owner as _=?, ~opts as _=?): component => Obj.magic(0)
146
146
  }
147
147
  let eventLog: EventLog.operations = {
148
148
  append: mock.appendFn,
@@ -188,7 +188,7 @@ module MakeOps = (B: {let name: string}) => {
188
188
  writeSnapshot: (string, EventLog.snapshot) => promise<result<unit, string>>,
189
189
  }
190
190
  type component = Component.t<OuterEventLog.t, OuterEventLog.outputs, operations>
191
- let make = (~name as _: string, ~opts as _=?): component => Obj.magic(0)
191
+ let make = (~name as _: string, ~owner as _=?, ~opts as _=?): component => Obj.magic(0)
192
192
  }
193
193
  let eventLog: EventLog.operations = {
194
194
  append: mock.appendFn,
@@ -84,7 +84,7 @@ module MockEventTopic: EventTopic.T
84
84
  publishJsonStream: ReventlessInfra.EventTopic.publishJsonStream,
85
85
  }
86
86
  type component = Component.t<EventTopic.t, EventTopic.outputs, operations>
87
- let make = (~name as _, ~storageResources as _, ~opts as _=?): component => Obj.magic(0)
87
+ let make = (~name as _, ~storageResources as _, ~owner as _=?, ~opts as _=?): component => Obj.magic(0)
88
88
  }
89
89
 
90
90
  let mockEventTopicOps: MockEventTopic.operations = {