@reventlessdev/reventless-core 3.0.0-alpha.284 → 3.0.0-alpha.285

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.
@@ -8,10 +8,12 @@ import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.
8
8
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
9
9
  import * as Effect from "effect/Effect";
10
10
  import * as Stream$1 from "effect/Stream";
11
+ import * as Owner$Reventless from "@reventlessdev/reventless-spec/src/components/Owner.res.mjs";
11
12
  import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
12
13
  import * as Lru$ReventlessCore from "../../util/Lru.res.mjs";
13
14
  import * as DcbDecode$Reventless from "@reventlessdev/reventless-spec/src/components/DcbDecode.res.mjs";
14
15
  import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
16
+ import * as OwnerScope$Reventless from "@reventlessdev/reventless-spec/src/types/OwnerScope.res.mjs";
15
17
  import * as Message$ReventlessCore from "../../Message.res.mjs";
16
18
  import * as Metrics$ReventlessCore from "../../util/Metrics.res.mjs";
17
19
  import * as LogFormat$ReventlessCore from "../../util/LogFormat.res.mjs";
@@ -37,6 +39,8 @@ function Make(Spec) {
37
39
  }
38
40
  });
39
41
  let scopeShape = DcbTag$Reventless.sliceShapeFromSchemas(Spec.name, Spec.commandSchema, Spec.consumedEventSchema, Spec.eventSchema, undefined);
42
+ let ownerFieldsByEventType = Owner$Reventless.fieldNamesByVariant(Spec.consumedEventSchema);
43
+ let actsOnOwned = Object.keys(ownerFieldsByEventType).length !== 0;
40
44
  let readEventId = (partitionTag, tags) => {
41
45
  let ownTagValues = () => {
42
46
  let vals = Stdlib_Array.reduce(tags, [], (acc, t) => {
@@ -104,6 +108,26 @@ function Make(Spec) {
104
108
  } else {
105
109
  entityId = undefined;
106
110
  }
111
+ let ownerFieldsOf = raw => {
112
+ if (partitionTag !== undefined) {
113
+ if (entityId !== undefined) {
114
+ if (actsOnOwned && DcbTag$Reventless.partitionValueOfTags(raw.tags, partitionTag) === entityId) {
115
+ return Stdlib_Option.getOr(ownerFieldsByEventType[raw.eventType], []);
116
+ } else {
117
+ return [];
118
+ }
119
+ } else {
120
+ return [];
121
+ }
122
+ } else {
123
+ return [];
124
+ }
125
+ };
126
+ let ownershipRefusal = owners => {
127
+ if (actsOnOwned) {
128
+ return CommandTopic_Helpers$ReventlessCore.ownershipRefusal(OwnerScope$Reventless.decideActing(command$p.meta.callerClaim, Stdlib_Option.map(entityId, param => owners)), Spec.name, Message$ReventlessCore.variantNameOfJson(cmdJson.commandJson));
129
+ }
130
+ };
107
131
  let cacheKey = JSON.stringify(query);
108
132
  let cacheGet = () => {
109
133
  if (cacheKey !== undefined) {
@@ -128,10 +152,12 @@ function Make(Spec) {
128
152
  let match = seed.contents;
129
153
  let match$1 = match !== undefined ? [
130
154
  match[0],
131
- match[1]
155
+ match[1],
156
+ match[2]
132
157
  ] : [
133
158
  Behavior.initialState,
134
- undefined
159
+ undefined,
160
+ []
135
161
  ];
136
162
  let afterPos = match$1[1];
137
163
  let cacheHit = Stdlib_Option.isSome(seed.contents);
@@ -148,12 +174,17 @@ function Make(Spec) {
148
174
  break;
149
175
  }
150
176
  return Effect.flatMap(Effect.tap(Stream$1.runFold(Stream$1.flatMap(Stream$1.map(dcbEventLog.readStream(query, afterPos, strongConsistency), raw => {
151
- let decoded = decoder.decode(raw.eventType, Stdlib_Option.getOr(Stdlib_JSON.Decode.object(raw.data), {}));
177
+ let data = Stdlib_Option.getOr(Stdlib_JSON.Decode.object(raw.data), {});
178
+ let decoded = decoder.decode(raw.eventType, data);
152
179
  return Stdlib_Option.map(decoded, event => [
153
180
  event,
154
181
  raw.position,
155
182
  raw.eventType,
156
- readEventId(partitionTag, raw.tags)
183
+ readEventId(partitionTag, raw.tags),
184
+ [
185
+ ownerFieldsOf(raw),
186
+ data
187
+ ]
157
188
  ]);
158
189
  }), opt => {
159
190
  if (opt !== undefined) {
@@ -164,14 +195,17 @@ function Make(Spec) {
164
195
  }), [
165
196
  match$1[0],
166
197
  afterPos,
167
- []
198
+ [],
199
+ match$1[2]
168
200
  ], (param, param$1) => {
201
+ let match = param$1[4];
169
202
  let eventId = param$1[3];
170
203
  let eventType = param$1[2];
171
204
  return [
172
205
  Behavior.evolve(param[0], param$1[0]),
173
206
  param$1[1],
174
- param[2].concat([eventId !== undefined ? LogFormat$ReventlessCore.bold(eventType) + `(` + eventId + `)` : LogFormat$ReventlessCore.bold(eventType)])
207
+ param[2].concat([eventId !== undefined ? LogFormat$ReventlessCore.bold(eventType) + `(` + eventId + `)` : LogFormat$ReventlessCore.bold(eventType)]),
208
+ OwnerScope$Reventless.recordOwners(param[3], match[0], match[1])
175
209
  ];
176
210
  }), param => {
177
211
  let reads = param[2];
@@ -184,16 +218,33 @@ function Make(Spec) {
184
218
  reads.length === 0 ? "" : ` [` + reads.join(", ") + `]`
185
219
  ));
186
220
  }), param => {
221
+ let owners = param[3];
187
222
  let headPosition = param[1];
188
223
  let state = param[0];
189
224
  return Effect.flatMap(EffectLogger$ReventlessCore.logDebug(comp, undefined, `deciding: id=` + Stdlib_Option.getOr(entityId, "-") + ` head=` + Stdlib_Option.getOr(headPosition, "-") + ` cmd=` + LogFormat$ReventlessCore.cmdName(cmdJson)), () => {
225
+ let match = ownershipRefusal(owners);
226
+ if (match !== undefined) {
227
+ let rejected = match.rejected;
228
+ cachePut([
229
+ state,
230
+ headPosition,
231
+ owners
232
+ ]);
233
+ CommandTopic_Helpers$ReventlessCore.reportRejected(Spec.name, "AccessRefusal", cmdJson.meta.msgId, rejected);
234
+ let line = `refused: ` + rejected.errorDetail + ` id=` + Stdlib_Option.getOr(entityId, "-");
235
+ return Effect.map(match.isDefect ? EffectLogger$ReventlessCore.logError(comp, undefined, line) : EffectLogger$ReventlessCore.logWarn(comp, undefined, line), () => ({
236
+ TAG: "Ok",
237
+ _0: "rejected"
238
+ }));
239
+ }
190
240
  let newEvents = Behavior.decide(state, command$p.command);
191
241
  if (newEvents.TAG === "Ok") {
192
242
  let newEvents$1 = newEvents._0;
193
243
  if (newEvents$1.length === 0) {
194
244
  cachePut([
195
245
  state,
196
- headPosition
246
+ headPosition,
247
+ owners
197
248
  ]);
198
249
  CommandTopic_Helpers$ReventlessCore.reportAccepted(Spec.name, cmdJson.meta.msgId, entityId !== undefined ? ({
199
250
  entityId: entityId,
@@ -243,7 +294,8 @@ function Make(Spec) {
243
294
  if (appendResult.TAG === "Ok") {
244
295
  cachePut([
245
296
  state,
246
- headPosition
297
+ headPosition,
298
+ owners
247
299
  ]);
248
300
  CommandTopic_Helpers$ReventlessCore.reportAccepted(Spec.name, cmdJson.meta.msgId, entityId !== undefined ? ({
249
301
  entityId: entityId,
@@ -270,7 +322,8 @@ function Make(Spec) {
270
322
  if (retries > 0) {
271
323
  seed.contents = [
272
324
  state,
273
- headPosition
325
+ headPosition,
326
+ owners
274
327
  ];
275
328
  Metrics$ReventlessCore.emitCount("AppendRetry", Spec.name, undefined);
276
329
  return Effect.flatMap(EffectLogger$ReventlessCore.logWarn(comp, undefined, `append failed (retrying ` + ((3 - retries | 0) + 1 | 0).toString() + `/` + (3).toString() + `): ` + errDetail), () => attempt(retries - 1 | 0));
@@ -292,12 +345,13 @@ function Make(Spec) {
292
345
  }
293
346
  cachePut([
294
347
  state,
295
- headPosition
348
+ headPosition,
349
+ owners
296
350
  ]);
297
351
  let errorJson = Util_Sury$Reventless.toJson(newEvents._0, Spec.errorSchema);
298
352
  let errorCode = Message$ReventlessCore.variantNameOfJson(errorJson);
299
- let match = Message$ReventlessCore.splitMessage(errorJson);
300
- let payloadDict = match[1];
353
+ let match$1 = Message$ReventlessCore.splitMessage(errorJson);
354
+ let payloadDict = match$1[1];
301
355
  let errorDetail = Object.entries(payloadDict).length === 0 ? "" : JSON.stringify(payloadDict);
302
356
  CommandTopic_Helpers$ReventlessCore.reportRejected(Spec.name, "DomainRejection", cmdJson.meta.msgId, {
303
357
  errorCode: errorCode,
@@ -783,6 +783,15 @@ type pluginDeployedInfo = {
783
783
  deployedAt: string,
784
784
  actor: string,
785
785
  deploymentId: string,
786
+ /** The commit the deployment was built from, when CI or git could say. */
787
+ commit?: string,
788
+ /** The working tree had changes the commit does not hold. */
789
+ dirty?: bool,
790
+ /** What the environment is for, from the app's `environments.yaml`. */
791
+ purpose?: string,
792
+ tag?: string,
793
+ /** The pull request a review environment was deployed for. */
794
+ pullRequest?: int,
786
795
  kind?: pluginKind,
787
796
  displayName?: string,
788
797
  vendor?: string,
@@ -1237,21 +1246,34 @@ let getInteropMeta = (): Pulumi.Output.t<JSON.t> => {
1237
1246
  }
1238
1247
 
1239
1248
  // ---------------------------------------------------------------------------
1240
- // Stack metadata export — environment, region, timestamp, actor, git SHA.
1249
+ // Stack metadata export — environment, region, timestamp, actor, commit.
1241
1250
  // Called from both exportPluginOutputs and exportPlatformOutputs.
1242
1251
  // ---------------------------------------------------------------------------
1243
1252
  let exportDeploymentMetadata = () => {
1253
+ let provenance = Reventless.DeploymentProvenance.current()
1254
+ let stack = Pulumi.Pulumi.getStackName()
1255
+ let optional =
1256
+ [
1257
+ ("commit", provenance.commit),
1258
+ ("purpose", provenance.purpose),
1259
+ ("tag", provenance.tag),
1260
+ ("pullRequest", provenance.pullRequest->Option.map(n => n->Int.toString)),
1261
+ ]->Array.filterMap(((key, value)) => value->Option.map(v => (key, v)))
1244
1262
  let metadata =
1245
1263
  [
1246
- ("environment", Pulumi.Pulumi.getStackName()),
1264
+ ("environment", provenance.environment->Option.getOr(stack)),
1265
+ ("stack", stack),
1247
1266
  (
1248
1267
  "region",
1249
1268
  Pulumi.Config.make(Some("aws"))->Pulumi.Config.get("region")->Option.getOr("unknown"),
1250
1269
  ),
1251
1270
  ("timestamp", Date.make()->Date.toISOString),
1252
- ("gitSha", NodeProcess.env->Dict.get("GITHUB_SHA")->Option.getOr("unknown")),
1271
+ ("gitSha", provenance.commit->Option.getOr("unknown")),
1272
+ ("dirty", provenance.dirty ? "true" : "false"),
1253
1273
  ("actor", NodeProcess.env->Dict.get("GITHUB_ACTOR")->Option.getOr("unknown")),
1254
- ]->Dict.fromArray
1274
+ ]
1275
+ ->Array.concat(optional)
1276
+ ->Dict.fromArray
1255
1277
  Pulumi.Pulumi.export(
1256
1278
  "deploymentMetadata",
1257
1279
  metadata->Dict.mapValues(JSON.Encode.string)->JSON.Encode.object->Pulumi.Output.make,
@@ -1595,6 +1617,7 @@ let exportPluginOutputs = (pluginOutputs: Plugin.outputs) => {
1595
1617
  ->Dict.get("GITHUB_SHA")
1596
1618
  ->Option.orElse(NodeProcess.env->Dict.get("CI_COMMIT_SHA"))
1597
1619
  ->Option.getOr(Date.make()->Date.toISOString)
1620
+ let provenance = Reventless.DeploymentProvenance.current()
1598
1621
  let schemaFor = name => componentSchemaRegistry->Dict.get(name)->Option.getOr({})
1599
1622
  let resolveAggregates = pluginOutputs.aggregates->Pulumi.Output.flatMap(aggs =>
1600
1623
  aggs
@@ -1855,11 +1878,16 @@ let exportPluginOutputs = (pluginOutputs: Plugin.outputs) => {
1855
1878
  let info: pluginDeployedInfo = {
1856
1879
  name,
1857
1880
  version,
1858
- environment: Pulumi.Pulumi.getStackName(),
1881
+ environment: provenance.environment->Option.getOr(Pulumi.Pulumi.getStackName()),
1859
1882
  stackName: Pulumi.Pulumi.getStackName(),
1860
1883
  deployedAt: Date.make()->Date.toISOString,
1861
1884
  actor,
1862
1885
  deploymentId,
1886
+ commit: ?provenance.commit,
1887
+ dirty: ?(provenance.dirty ? Some(true) : None),
1888
+ purpose: ?provenance.purpose,
1889
+ tag: ?provenance.tag,
1890
+ pullRequest: ?provenance.pullRequest,
1863
1891
  kind: ?(meta->Option.flatMap(m => m.kind)),
1864
1892
  displayName: ?(meta->Option.flatMap(m => m.displayName)),
1865
1893
  vendor: ?(meta->Option.flatMap(m => m.vendor)),
@@ -42,6 +42,7 @@ import * as ApiNoApiHelpers$ReventlessCore from "../../components/Api/ApiNoApiHe
42
42
  import * as AutomationSlice$ReventlessCore from "../../components/AutomationSlice/AutomationSlice.res.mjs";
43
43
  import * as Builder_Helpers$ReventlessCore from "../../components/Builder_Helpers.res.mjs";
44
44
  import * as Plugin_Callback$ReventlessCore from "./Plugin_Callback.res.mjs";
45
+ import * as DeploymentProvenance$Reventless from "@reventlessdev/reventless-spec/src/types/DeploymentProvenance.res.mjs";
45
46
  import * as Plugin_BuiltHook$ReventlessCore from "./Plugin_BuiltHook.res.mjs";
46
47
  import * as StateChangeSlice$ReventlessCore from "../../components/StateChangeSlice/StateChangeSlice.res.mjs";
47
48
  import * as ExtensionPoint$ReventlessInterop from "@reventlessdev/reventless-interop/src/components/ExtensionPoint.res.mjs";
@@ -607,10 +608,40 @@ function getInteropMeta() {
607
608
  }
608
609
 
609
610
  function exportDeploymentMetadata() {
611
+ let provenance = DeploymentProvenance$Reventless.current();
612
+ let stack = Pulumi.getStack();
613
+ let optional = Stdlib_Array.filterMap([
614
+ [
615
+ "commit",
616
+ provenance.commit
617
+ ],
618
+ [
619
+ "purpose",
620
+ provenance.purpose
621
+ ],
622
+ [
623
+ "tag",
624
+ provenance.tag
625
+ ],
626
+ [
627
+ "pullRequest",
628
+ Stdlib_Option.map(provenance.pullRequest, n => n.toString())
629
+ ]
630
+ ], param => {
631
+ let key = param[0];
632
+ return Stdlib_Option.map(param[1], v => [
633
+ key,
634
+ v
635
+ ]);
636
+ });
610
637
  let metadata = Object.fromEntries([
611
638
  [
612
639
  "environment",
613
- Pulumi.getStack()
640
+ Stdlib_Option.getOr(provenance.environment, stack)
641
+ ],
642
+ [
643
+ "stack",
644
+ stack
614
645
  ],
615
646
  [
616
647
  "region",
@@ -622,13 +653,17 @@ function exportDeploymentMetadata() {
622
653
  ],
623
654
  [
624
655
  "gitSha",
625
- Stdlib_Option.getOr(process.env["GITHUB_SHA"], "unknown")
656
+ Stdlib_Option.getOr(provenance.commit, "unknown")
657
+ ],
658
+ [
659
+ "dirty",
660
+ provenance.dirty ? "true" : "false"
626
661
  ],
627
662
  [
628
663
  "actor",
629
664
  Stdlib_Option.getOr(process.env["GITHUB_ACTOR"], "unknown")
630
665
  ]
631
- ]);
666
+ ].concat(optional));
632
667
  Pulumi$Pulumi.$$export("deploymentMetadata", Pulumi.output(Stdlib_Dict.mapValues(metadata, prim => prim)));
633
668
  }
634
669
 
@@ -725,6 +760,7 @@ function exportPluginOutputs(pluginOutputs) {
725
760
  }
726
761
  let actor = Stdlib_Option.getOr(Stdlib_Option.orElse(Stdlib_Option.orElse(process.env["GITHUB_ACTOR"], process.env["CI_COMMIT_AUTHOR"]), process.env["USER"]), "local");
727
762
  let deploymentId = Stdlib_Option.getOr(Stdlib_Option.orElse(process.env["GITHUB_SHA"], process.env["CI_COMMIT_SHA"]), new Date().toISOString());
763
+ let provenance = DeploymentProvenance$Reventless.current();
728
764
  let resolveAggregates = Output$Pulumi.flatMap(pluginOutputs.aggregates, aggs => Pulumi.all(Object.entries(aggs).map(param => {
729
765
  let name = param[0];
730
766
  return Aggregate$ReventlessCore.toResolvedOutputs(param[1]).apply(resolved => ({
@@ -904,11 +940,16 @@ function exportPluginOutputs(pluginOutputs) {
904
940
  return hook({
905
941
  name: name,
906
942
  version: version,
907
- environment: Pulumi.getStack(),
943
+ environment: Stdlib_Option.getOr(provenance.environment, Pulumi.getStack()),
908
944
  stackName: Pulumi.getStack(),
909
945
  deployedAt: new Date().toISOString(),
910
946
  actor: actor,
911
947
  deploymentId: deploymentId,
948
+ commit: provenance.commit,
949
+ dirty: provenance.dirty ? true : undefined,
950
+ purpose: provenance.purpose,
951
+ tag: provenance.tag,
952
+ pullRequest: provenance.pullRequest,
912
953
  kind: Stdlib_Option.flatMap(meta, m => m.kind),
913
954
  displayName: Stdlib_Option.flatMap(meta, m => m.displayName),
914
955
  vendor: Stdlib_Option.flatMap(meta, m => m.vendor),