@reventlessdev/reventless-aws 3.0.0-alpha.397 → 3.0.0-alpha.398

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 (83) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/package.json +9 -9
  3. package/scripts/BakeManifest.res +15 -15
  4. package/scripts/DeployApp.res +8 -9
  5. package/scripts/DeployApp.res.mjs +4 -13
  6. package/scripts/DeployManifest.res +4 -5
  7. package/scripts/DeployManifest.res.mjs +0 -1
  8. package/scripts/ProvisionAccounts.res +41 -33
  9. package/scripts/ProvisionAccounts.res.mjs +6 -9
  10. package/scripts/ProvisionAdmin.res +10 -10
  11. package/scripts/ProvisionIdentity.res +2 -2
  12. package/scripts/ResolveEnvironment.res +3 -3
  13. package/src/Platform.res +6 -4
  14. package/src/Platform.res.mjs +6 -4
  15. package/src/Platform_ProvidedGroups.res +4 -4
  16. package/src/Platform_Stack.res +2 -3
  17. package/src/Platform_Stack.res.mjs +1 -2
  18. package/src/adapter/Api/AppSyncEventsSigner_Ops.res +2 -2
  19. package/src/adapter/Api/AppSync_EventsApi.res +2 -2
  20. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +6 -6
  21. package/src/adapter/DcbEventLog/DcbBackend.res +3 -3
  22. package/src/adapter/DcbEventLog/DcbBackend.res.mjs +1 -3
  23. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +11 -9
  24. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res.mjs +4 -6
  25. package/src/adapter/EventLog/EventLogBackend.res +3 -3
  26. package/src/adapter/EventLog/EventLogBackend.res.mjs +1 -3
  27. package/src/adapter/Geocoder/Geocoder_AwsLocation_Backend.res +1 -1
  28. package/src/adapter/QueryDb/PgQueryResolver_Lambda.res +5 -5
  29. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +2 -2
  30. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +2 -2
  31. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +32 -32
  32. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +4 -3
  33. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +6 -6
  34. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +16 -5
  35. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res.mjs +3 -3
  36. package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +5 -5
  37. package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +24 -18
  38. package/src/adapter/Runtime/ReadModelEntryPoint_Ops.res +16 -14
  39. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +2 -2
  40. package/src/adapter/Runtime/RuntimeExtensionEntryPoint_Ops.res +4 -4
  41. package/src/adapter/Runtime/SideEffectEntryPoint_Ops.res +4 -4
  42. package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +9 -9
  43. package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +11 -9
  44. package/src/components/Api/AppSync_Adapter.res +4 -4
  45. package/src/components/InboundTranslationSlice_Builder.res +19 -0
  46. package/src/components/InboundTranslationSlice_Builder.res.mjs +12 -2
  47. package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +4 -7
  48. package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res.mjs +1 -4
  49. package/src/plugin/runtime/PluginRuntime_Builder.res +17 -26
  50. package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +7 -22
  51. package/tests/AppSyncEventsSigner_OpsTest.res +1 -1
  52. package/tests/AppSync_AdapterTest.res +4 -4
  53. package/tests/AppSync_AdapterTest.res.mjs +4 -8
  54. package/tests/Auth_ActiveRoleStoreTest.res +1 -1
  55. package/tests/Auth_ActiveRoleTrigger_OpsTest.res +1 -1
  56. package/tests/AutomationSliceEntryPoint_OpsTest.res +0 -2
  57. package/tests/AutomationSliceEntryPoint_OpsTest.res.mjs +3 -6
  58. package/tests/BakeConvergenceTest.res +1 -8
  59. package/tests/BakeConvergenceTest.res.mjs +3 -23
  60. package/tests/BakeManifestTest.res +5 -10
  61. package/tests/BakeManifestTest.res.mjs +1 -6
  62. package/tests/CommandLineTest.res +3 -3
  63. package/tests/DeployAppTest.res +3 -4
  64. package/tests/DeployAppTest.res.mjs +6 -15
  65. package/tests/EpInboundTestSlice.res +1 -0
  66. package/tests/EpInboundTestSlice.res.mjs +3 -0
  67. package/tests/EventCollectorPluginDefinitionAssetTest.res +1 -2
  68. package/tests/EventCollectorPluginDefinitionAssetTest.res.mjs +11 -21
  69. package/tests/IdentityProvider_Cognito_BackendTest.res +0 -3
  70. package/tests/IdentityProvider_Cognito_BackendTest.res.mjs +0 -3
  71. package/tests/PgQueryResolver_LambdaTest.res +6 -10
  72. package/tests/PgQueryResolver_LambdaTest.res.mjs +4 -34
  73. package/tests/Platform_ProvidedGroupsTest.res +2 -2
  74. package/tests/Platform_ProvidedGroupsTest.res.mjs +1 -2
  75. package/tests/ProvisionAccountsTest.res +5 -10
  76. package/tests/ProvisionAccountsTest.res.mjs +0 -9
  77. package/tests/ProvisionAdminTest.res +4 -9
  78. package/tests/ProvisionAdminTest.res.mjs +0 -7
  79. package/tests/ProvisionIdentityTest.res +2 -4
  80. package/tests/ProvisionIdentityTest.res.mjs +0 -2
  81. package/tests/SideEffectEntryPoint_OpsTest.res +2 -2
  82. package/tests/Util_ShellConfigTest.res +3 -3
  83. package/tests/Util_ShellConfigTest.res.mjs +1 -2
@@ -8,7 +8,7 @@ read outside any `Output.apply`.
8
8
 
9
9
  module Cognito = AwsSdk.CognitoIdentityServiceProvider
10
10
 
11
- type pool = {id: string, region: option<string>}
11
+ type pool = {id: string, region?: string}
12
12
 
13
13
  type send = Cognito.ListGroupsCommand.input => promise<Cognito.ListGroupsCommand.output>
14
14
 
@@ -39,7 +39,7 @@ let poolFromExports = (~get: string => option<JSON.t>): option<pool> => {
39
39
  ->Option.orElse(read("cognitoUserPoolId"))
40
40
  ->Option.map(id => {
41
41
  id,
42
- region: read("identityProviderRegion")->Option.orElse(read("cognitoRegion")),
42
+ region: ?(read("identityProviderRegion")->Option.orElse(read("cognitoRegion"))),
43
43
  })
44
44
  }
45
45
 
@@ -72,7 +72,7 @@ let resolvePool = async (~stackRef: option<Pulumi.StackReference.t>): option<poo
72
72
  ~cfg=Pulumi.Config.make(Some("platform")),
73
73
  )->Option.map(id => {
74
74
  id,
75
- region: Pulumi.Config.make(Some("aws"))->Pulumi.Config.get("region"),
75
+ region: ?(Pulumi.Config.make(Some("aws"))->Pulumi.Config.get("region")),
76
76
  })
77
77
  }
78
78
 
@@ -86,7 +86,7 @@ let sendTo = (~region: option<string>): send => {
86
86
  let load = async (~stackRef: option<Pulumi.StackReference.t>): unit =>
87
87
  switch await resolvePool(~stackRef) {
88
88
  | None => ()
89
- | Some({id, region}) =>
89
+ | Some({id, ?region}) =>
90
90
  let groups = try await listAll(~send=sendTo(~region), ~userPoolId=id) catch {
91
91
  | exn if exn->Util_AwsError.hasCode(~code="AccessDeniedException") =>
92
92
  JsError.throwWithMessage(
@@ -18,7 +18,7 @@ type cognitoUserPool = {
18
18
  /** The sign-in attribute this stack created the pool with. `None` in BYO mode:
19
19
  the pool's own choice was made elsewhere and no lookup here reads it back,
20
20
  so reporting one would be a guess. */
21
- loginIdentifier: option<Auth_LoginIdentifier.t>,
21
+ loginIdentifier?: Auth_LoginIdentifier.t,
22
22
  }
23
23
 
24
24
  /**
@@ -250,7 +250,6 @@ let _resolveUncached = (): cognitoUserPool => {
250
250
  managed: false,
251
251
  activeRoleTable,
252
252
  identityTable,
253
- loginIdentifier: None,
254
253
  }
255
254
 
256
255
  | None =>
@@ -346,7 +345,7 @@ let _resolveUncached = (): cognitoUserPool => {
346
345
  managed: true,
347
346
  activeRoleTable,
348
347
  identityTable,
349
- loginIdentifier: Some(loginIdentifier),
348
+ loginIdentifier,
350
349
  }
351
350
  }
352
351
 
@@ -107,8 +107,7 @@ function _resolveUncached() {
107
107
  poolArn: lookup.apply(r => r.arn),
108
108
  managed: false,
109
109
  activeRoleTable: activeRoleTable,
110
- identityTable: identityTable,
111
- loginIdentifier: undefined
110
+ identityTable: identityTable
112
111
  };
113
112
  } else {
114
113
  let loginIdentifier = _loginIdentifier(cfg);
@@ -23,13 +23,13 @@ let hmacFromBuf = (key: NodeCrypto.buffer, data: string): NodeCrypto.buffer =>
23
23
 
24
24
  // ── SigV4 ───────────────────────────────────────────────────────────────────
25
25
 
26
- type creds = {accessKeyId: string, secretAccessKey: string, sessionToken: option<string>}
26
+ type creds = {accessKeyId: string, secretAccessKey: string, sessionToken?: string}
27
27
 
28
28
  // Ambient Lambda execution-role credentials (the managed runtime injects these).
29
29
  let envCreds = (): creds => {
30
30
  accessKeyId: NodeProcess.env->Dict.get("AWS_ACCESS_KEY_ID")->Option.getOr(""),
31
31
  secretAccessKey: NodeProcess.env->Dict.get("AWS_SECRET_ACCESS_KEY")->Option.getOr(""),
32
- sessionToken: NodeProcess.env->Dict.get("AWS_SESSION_TOKEN"),
32
+ sessionToken: ?(NodeProcess.env->Dict.get("AWS_SESSION_TOKEN")),
33
33
  }
34
34
 
35
35
  let region = (): string => NodeProcess.env->Dict.get("AWS_REGION")->Option.getOr("eu-west-1")
@@ -80,7 +80,7 @@ type t = {
80
80
  /** Full AppSync Events API output — carry this through the stack. */
81
81
  api: Api.t,
82
82
  /** The `default` channel namespace created on the API. */
83
- defaultNamespace: option<ChannelNamespace.t>,
83
+ defaultNamespace?: ChannelNamespace.t,
84
84
  /** The client-publishable `client` namespace. Absent on plugin-stack
85
85
  phantoms (namespaces live on the platform stack's API). */
86
86
  clientNamespace?: ChannelNamespace.t,
@@ -202,7 +202,7 @@ let make = (
202
202
  ~opts=Some({...opts, parent: api->Pulumi.Resource.makeFromJs}),
203
203
  )
204
204
 
205
- {name, api, defaultNamespace: Some(defaultNamespace), clientNamespace}
205
+ {name, api, defaultNamespace, clientNamespace}
206
206
  }
207
207
 
208
208
  /** HTTP endpoint URL for use as Lambda `APPSYNC_ENDPOINT` env var.
@@ -334,9 +334,9 @@ let bakeSelection = (json: JSON.t): option<ReventlessCore.Platform_BakedManifest
334
334
  ->Option.flatMap(JSON.Decode.string)
335
335
  ->Option.map(plugin => {
336
336
  ReventlessCore.Platform_BakedManifest.plugin,
337
- views: strings(o, "views"),
338
- commands: strings(o, "commands"),
339
- derived: strings(o, "derived"),
337
+ views: ?strings(o, "views"),
338
+ commands: ?strings(o, "commands"),
339
+ derived: ?strings(o, "derived"),
340
340
  })
341
341
  )
342
342
  }
@@ -502,8 +502,8 @@ type registrationState =
502
502
  type registration = {
503
503
  plugin: string,
504
504
  expected: string,
505
- found: option<string>,
506
- writtenAt: option<string>,
505
+ found?: string,
506
+ writtenAt?: string,
507
507
  state: registrationState,
508
508
  }
509
509
 
@@ -550,7 +550,7 @@ let registrations = (
550
550
  let row = current->Dict.get(plugin)
551
551
  let found = row->Option.map(((key, _)) => key)
552
552
  let writtenAt = row->Option.flatMap(((_, at)) => at)
553
- {plugin, expected, found, writtenAt, state: classify(~expected, ~found, ~writtenAt, ~since)}
553
+ {plugin, expected, ?found, ?writtenAt, state: classify(~expected, ~found, ~writtenAt, ~since)}
554
554
  })
555
555
  }
556
556
 
@@ -53,8 +53,8 @@ let isPostgres = (): bool => selectionRef.contents->Option.isSome
53
53
  type relayLogEntry = {
54
54
  logName: string,
55
55
  partitionTag: Reventless.DcbTag.derivedPartitionTag,
56
- mutable collectorQueueUrl: option<Pulumi.Output.t<string>>,
57
- mutable collectorQueueArn: option<Pulumi.Output.t<string>>,
56
+ mutable collectorQueueUrl?: Pulumi.Output.t<string>,
57
+ mutable collectorQueueArn?: Pulumi.Output.t<string>,
58
58
  }
59
59
 
60
60
  let relayLogs: array<relayLogEntry> = []
@@ -62,7 +62,7 @@ let relayLogs: array<relayLogEntry> = []
62
62
  /** Step 1: record a Postgres DCB log and its partition tag (from the storage maker). */
63
63
  let registerRelayLog = (~logName: string, ~partitionTag: Reventless.DcbTag.derivedPartitionTag) =>
64
64
  relayLogs
65
- ->Array.push({logName, partitionTag, collectorQueueUrl: None, collectorQueueArn: None})
65
+ ->Array.push({logName, partitionTag})
66
66
  ->ignore
67
67
 
68
68
  /** Step 2: attach a plugin's EventCollector SQS queue to its DCB log's relay entry. */
@@ -23,9 +23,7 @@ let relayLogs = [];
23
23
  function registerRelayLog(logName, partitionTag) {
24
24
  relayLogs.push({
25
25
  logName: logName,
26
- partitionTag: partitionTag,
27
- collectorQueueUrl: undefined,
28
- collectorQueueArn: undefined
26
+ partitionTag: partitionTag
29
27
  });
30
28
  }
31
29
 
@@ -265,9 +265,9 @@ let queryByCompositeTags = async (
265
265
 
266
266
  // Filter clause shared by both scan paths.
267
267
  type scanFilter = {
268
- filterExpression: option<string>,
269
- expressionAttributeNames: option<Dict.t<string>>,
270
- expressionAttributeValues: option<Dict.t<JSON.t>>,
268
+ filterExpression?: string,
269
+ expressionAttributeNames?: Dict.t<string>,
270
+ expressionAttributeValues?: Dict.t<JSON.t>,
271
271
  }
272
272
 
273
273
  // Builds the scan FilterExpression. Always asserts `attribute_exists(event)` so
@@ -294,9 +294,9 @@ let buildScanFilter = (~eventTypes: option<array<string>>=?): scanFilter => {
294
294
 
295
295
  let hasAttributeValues = expressionAttributeValues->Dict.keysToArray->Array.length > 0
296
296
  {
297
- filterExpression: Some(filterParts->Array.join(" AND ")),
298
- expressionAttributeNames: Some(expressionAttributeNames),
299
- expressionAttributeValues: hasAttributeValues ? Some(expressionAttributeValues) : None,
297
+ filterExpression: filterParts->Array.join(" AND "),
298
+ expressionAttributeNames,
299
+ expressionAttributeValues: ?(hasAttributeValues ? Some(expressionAttributeValues) : None),
300
300
  }
301
301
  }
302
302
 
@@ -523,7 +523,7 @@ let deduplicateByPosition = (
523
523
 
524
524
  type mergeSlot = {
525
525
  queue: Queue.t<option<ReventlessCore.DcbEventLog_Adapter.rawSequencedEvent>>,
526
- head: option<ReventlessCore.DcbEventLog_Adapter.rawSequencedEvent>,
526
+ head?: ReventlessCore.DcbEventLog_Adapter.rawSequencedEvent,
527
527
  }
528
528
 
529
529
  // Wraps a sub-stream in a Queue(1) producer fiber and pulls the first element.
@@ -539,7 +539,9 @@ let initSlot = (
539
539
  // unhandled-fiber-failure warning).
540
540
  ->Effect.ensuring(Queue.offer(queue, None)->Effect.map(_ => ()))
541
541
  ->Effect.catchAll(_ => Effect.succeed())
542
- Effect.fork(producer)->Effect.flatMap(_ => Queue.take(queue)->Effect.map(head => {queue, head}))
542
+ Effect.fork(producer)->Effect.flatMap(_ =>
543
+ Queue.take(queue)->Effect.map(head => {queue, ?head})
544
+ )
543
545
  })
544
546
 
545
547
  // Returns the index of the slot with the smallest position, or None if all exhausted.
@@ -596,7 +598,7 @@ let mergeSortedEvents = (
596
598
  let newSlots = slots->Array.mapWithIndex(
597
599
  (s, i) =>
598
600
  if i == idx {
599
- {...s, head: nextHead}
601
+ {...s, head: ?nextHead}
600
602
  } else {
601
603
  s
602
604
  },
@@ -468,14 +468,12 @@ function mergeSortedEvents(streams) {
468
468
  let emitEvent = Stdlib_Option.getOrThrow(slot.head, undefined);
469
469
  return Effect$1.map(Queue.take(slot.queue), nextHead => {
470
470
  let newSlots = slots.map((s, i) => {
471
- if (i === idx) {
472
- return {
473
- queue: s.queue,
474
- head: nextHead
475
- };
476
- } else {
471
+ if (i !== idx) {
477
472
  return s;
478
473
  }
474
+ let newrecord = {...s};
475
+ newrecord.head = nextHead;
476
+ return newrecord;
479
477
  });
480
478
  let hasActive = newSlots.some(s => Stdlib_Option.isSome(s.head));
481
479
  return [
@@ -53,8 +53,8 @@ let isPostgres = (): bool => selectionRef.contents->Option.isSome
53
53
  type relayLogEntry = {
54
54
  logName: string,
55
55
  aggregateName: string,
56
- mutable collectorQueueUrl: option<Pulumi.Output.t<string>>,
57
- mutable collectorQueueArn: option<Pulumi.Output.t<string>>,
56
+ mutable collectorQueueUrl?: Pulumi.Output.t<string>,
57
+ mutable collectorQueueArn?: Pulumi.Output.t<string>,
58
58
  }
59
59
 
60
60
  let relayLogs: array<relayLogEntry> = []
@@ -62,7 +62,7 @@ let relayLogs: array<relayLogEntry> = []
62
62
  /** Step 1: record a Postgres classic log (from the storage maker). */
63
63
  let registerRelayLog = (~logName: string, ~aggregateName: string) =>
64
64
  relayLogs
65
- ->Array.push({logName, aggregateName, collectorQueueUrl: None, collectorQueueArn: None})
65
+ ->Array.push({logName, aggregateName})
66
66
  ->ignore
67
67
 
68
68
  /** Step 2: attach a plugin's EventCollector SQS queue to one aggregate's relay entry. */
@@ -23,9 +23,7 @@ let relayLogs = [];
23
23
  function registerRelayLog(logName, aggregateName) {
24
24
  relayLogs.push({
25
25
  logName: logName,
26
- aggregateName: aggregateName,
27
- collectorQueueUrl: undefined,
28
- collectorQueueArn: undefined
26
+ aggregateName: aggregateName
29
27
  });
30
28
  }
31
29
 
@@ -57,7 +57,7 @@ let search = async (~indexName: string, ~text: string, ~maxResults: int=5): resu
57
57
  Some({
58
58
  Reventless.Geocoding.label: place.label->Option.getOr(""),
59
59
  point,
60
- relevance: r.relevance,
60
+ relevance: ?r.relevance,
61
61
  })
62
62
  // A coordinate that fails the range check is dropped rather than
63
63
  // propagated: it cannot be stored, and one bad row should not lose
@@ -89,7 +89,7 @@ type binding = {
89
89
  ops: ReventlessCore.QueryDb_Adapter.operations,
90
90
  pushdowns: pushdowns,
91
91
  indexes: array<Reventless.ReadModel.indexConfig>,
92
- subIdField: option<string>,
92
+ subIdField?: string,
93
93
  capability: ReventlessCore.GraphQL_FragmentGenerator.serverCapability,
94
94
  labelField: string,
95
95
  includeIdParam: bool,
@@ -97,9 +97,9 @@ type binding = {
97
97
  /** The state's `@owner` field, when it declares one. Derived at Lambda init
98
98
  from the same schema `capability` comes from, so the two cannot disagree
99
99
  about which fields this read model has. */
100
- ownerField: option<string>,
101
- retiredField: option<string>,
102
- retiredValues: option<array<string>>,
100
+ ownerField?: string,
101
+ retiredField?: string,
102
+ retiredValues?: array<string>,
103
103
  /** Whether a reference to a retired row of this read model still resolves its
104
104
  name — the `@namedWhenRetired` opt-in. Read only by the reference door;
105
105
  every other door narrows as it always did. */
@@ -107,7 +107,7 @@ type binding = {
107
107
  /** The field a reference shows this row's picture from, derived from the same
108
108
  schema as `capability` by `Reventless.RowImage`. `None` for a view that
109
109
  declares no picture, which is most of them. */
110
- imageSource: option<Reventless.RowImage.source>,
110
+ imageSource?: Reventless.RowImage.source,
111
111
  }
112
112
 
113
113
  // -- arg helpers -------------------------------------------------------------
@@ -11,7 +11,7 @@ type aggregateInfo = {
11
11
  specModulePath: string,
12
12
  decisionModulePath: string,
13
13
  eventLogTableName: Pulumi.Output.t<string>,
14
- mappingsModulePath: option<string>,
14
+ mappingsModulePath?: string,
15
15
  }
16
16
 
17
17
  let aggregateInfos: dict<aggregateInfo> = Dict.make()
@@ -25,7 +25,7 @@ let registerAggregate = (
25
25
  ) =>
26
26
  aggregateInfos->Dict.set(
27
27
  aggregateName,
28
- {specModulePath, decisionModulePath, eventLogTableName, mappingsModulePath},
28
+ {specModulePath, decisionModulePath, eventLogTableName, ?mappingsModulePath},
29
29
  )
30
30
 
31
31
  type storedSpec = {
@@ -15,7 +15,7 @@ type aggregateInfo = {
15
15
  specModulePath: string,
16
16
  decisionModulePath: string,
17
17
  eventLogTableName: Pulumi.Output.t<string>,
18
- mappingsModulePath: option<string>,
18
+ mappingsModulePath?: string,
19
19
  }
20
20
 
21
21
  let aggregateInfos: dict<aggregateInfo> = Dict.make()
@@ -29,7 +29,7 @@ let registerAggregate = (
29
29
  ) =>
30
30
  aggregateInfos->Dict.set(
31
31
  aggregateName,
32
- {specModulePath, decisionModulePath, eventLogTableName, mappingsModulePath},
32
+ {specModulePath, decisionModulePath, eventLogTableName, ?mappingsModulePath},
33
33
  )
34
34
 
35
35
  type storedSpec = {
@@ -29,11 +29,11 @@ type handlerEntry = {
29
29
  /** Whether `dcbQueueUrl` is a FIFO queue. Absent in a config written before
30
30
  the flavor travelled with the URL, where `false` — a standard queue — is
31
31
  what these command topics actually are. */
32
- commandQueueIsFifo: option<bool>,
32
+ commandQueueIsFifo?: bool,
33
33
  sourceUrn: string,
34
- context: option<Reventless.AutomationSlice.context>,
34
+ context?: Reventless.AutomationSlice.context,
35
35
  /** The slice's schedules store; absent for a slice that maps no `Clock`. */
36
- schedulesTableName: option<string>,
36
+ schedulesTableName?: string,
37
37
  }
38
38
 
39
39
  let strOf = (obj: dict<JSON.t>, key: string): option<string> =>
@@ -58,10 +58,10 @@ let decodeEntry = (json: JSON.t): option<handlerEntry> =>
58
58
  callbackType: h->strOf("callbackType")->Option.getOr("automation"),
59
59
  queryDbTableName: h->strOf("queryDbTableName")->Option.getOr(""),
60
60
  dcbQueueUrl: h->strOf("dcbQueueUrl")->Option.getOr(""),
61
- commandQueueIsFifo: h->Dict.get("commandQueueIsFifo")->Option.flatMap(JSON.Decode.bool),
61
+ commandQueueIsFifo: ?(h->Dict.get("commandQueueIsFifo")->Option.flatMap(JSON.Decode.bool)),
62
62
  sourceUrn: h->strOf("sourceUrn")->Option.getOr(""),
63
- context: h->Dict.get("context")->Option.flatMap(decodeContext),
64
- schedulesTableName: h->strOf("schedulesTableName"),
63
+ context: ?(h->Dict.get("context")->Option.flatMap(decodeContext)),
64
+ schedulesTableName: ?(h->strOf("schedulesTableName")),
65
65
  })
66
66
 
67
67
  // A compact entry names its slice and carries only what the deploy resolved;
@@ -91,15 +91,15 @@ let decodeCompactEntry = (
91
91
  callbackType: m->strOf("callbackType")->Option.getOr("automation"),
92
92
  queryDbTableName: h->strOf("q")->Option.getOr(""),
93
93
  dcbQueueUrl: h->strOf("k")->Option.getOr(sharedQueueUrl),
94
- commandQueueIsFifo: switch h->Dict.get("f")->Option.flatMap(JSON.Decode.bool) {
94
+ commandQueueIsFifo: ?switch h->Dict.get("f")->Option.flatMap(JSON.Decode.bool) {
95
95
  | Some(f) => Some(f)
96
96
  | None => sharedIsFifo
97
97
  },
98
98
  // Only the first, which is all the shell registers today. The remaining
99
99
  // urns stay in the config for the multi-source registration to use.
100
100
  sourceUrn: urns->Array.get(0)->Option.getOr(""),
101
- context: m->Dict.get("context")->Option.flatMap(decodeContext),
102
- schedulesTableName: h->strOf("s"),
101
+ context: ?(m->Dict.get("context")->Option.flatMap(decodeContext)),
102
+ schedulesTableName: ?(h->strOf("s")),
103
103
  }
104
104
  }
105
105
 
@@ -428,6 +428,9 @@ let capabilities = (): Reventless.Capabilities.t => {
428
428
  ~identityStore=NodeProcess.env->Dict.get("IDENTITY_STORE_TABLE")->Option.getOr(""),
429
429
  ),
430
430
  secrets: ReventlessCore.Secrets_Node_Backend.provider,
431
+ // None deployed yet: a slice declaring the need is refused by the deploy gate,
432
+ // and this answers `Unavailable` should one run regardless.
433
+ stash: Reventless.Capabilities.none.stash,
431
434
  }
432
435
 
433
436
  // ── Phase-1/phase-2 pipelines ───────────────────────────────────────────────
@@ -576,7 +579,7 @@ type builtSlice = {
576
579
  tick: option<(~key: string, ~at: float) => promise<unit>>,
577
580
  /** Brings the slice's schedules in line with its spec and its rows, at a deploy;
578
581
  `None` for an outbound slice. */
579
- reconcile: option<unit => promise<unit>>,
582
+ reconcile?: unit => promise<unit>,
580
583
  }
581
584
 
582
585
  let makeAutomationRegisteredHandler = (
@@ -651,27 +654,25 @@ let makeAutomationRegisteredHandler = (
651
654
  await syncTodoItems()
652
655
  },
653
656
  ),
654
- reconcile: Some(
655
- async () =>
656
- switch schedules() {
657
- | Some({load, sync, platform}) =>
658
- await load()
659
- await ReventlessCore.AutomationSlice_Schedules.reconcile(
660
- callback.schedules,
661
- platform,
662
- ~declaredTime=schedule,
663
- ~now=Date.now(),
664
- )
665
- await sync()
666
- // No Clock mapping, so no schedule of the slice may stay on the platform.
667
- | None =>
668
- let platform = platformSchedulesOf(~slice=sliceName)
669
- let names = await platform.names()
670
- for i in 0 to names->Array.length - 1 {
671
- await platform.removeName(names->Array.getUnsafe(i))
672
- }
673
- },
674
- ),
657
+ reconcile: async () =>
658
+ switch schedules() {
659
+ | Some({load, sync, platform}) =>
660
+ await load()
661
+ await ReventlessCore.AutomationSlice_Schedules.reconcile(
662
+ callback.schedules,
663
+ platform,
664
+ ~declaredTime=schedule,
665
+ ~now=Date.now(),
666
+ )
667
+ await sync()
668
+ // No Clock mapping, so no schedule of the slice may stay on the platform.
669
+ | None =>
670
+ let platform = platformSchedulesOf(~slice=sliceName)
671
+ let names = await platform.names()
672
+ for i in 0 to names->Array.length - 1 {
673
+ await platform.removeName(names->Array.getUnsafe(i))
674
+ }
675
+ },
675
676
  }
676
677
  }
677
678
 
@@ -718,7 +719,6 @@ let makeOutboundRegisteredHandler = (
718
719
  comp,
719
720
  name: sliceName,
720
721
  tick: None,
721
- reconcile: None,
722
722
  }
723
723
  }
724
724
 
@@ -13,6 +13,7 @@ import * as DcbDecode$Reventless from "@reventlessdev/reventless-spec/src/compon
13
13
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
14
14
  import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
15
15
  import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
16
+ import * as Capabilities$Reventless from "@reventlessdev/reventless-spec/src/semantic/Capabilities.res.mjs";
16
17
  import * as EffectLogger$ReventlessCore from "@reventlessdev/reventless-core/src/util/EffectLogger.res.mjs";
17
18
  import * as DynamoDb_Error$ReventlessAws from "../../errors/DynamoDb_Error.res.mjs";
18
19
  import * as Messaging_Ses_Backend$ReventlessAws from "../Messaging/Messaging_Ses_Backend.res.mjs";
@@ -276,7 +277,8 @@ function capabilities() {
276
277
  geocode: text => Geocoder_AwsLocation_Backend$ReventlessAws.search(Stdlib_Option.getOr(process.env["PLACE_INDEX_NAME"], ""), text, undefined),
277
278
  messaging: messagingEmailProvider(),
278
279
  identityProvider: IdentityProvider_Cognito_Backend$ReventlessAws.provider(Stdlib_Option.getOr(process.env["IDENTITY_PROVIDER_ID"], ""), Stdlib_Option.getOr(process.env["IDENTITY_STORE_TABLE"], "")),
279
- secrets: Secrets_Node_Backend$ReventlessCore.provider
280
+ secrets: Secrets_Node_Backend$ReventlessCore.provider,
281
+ stash: Capabilities$Reventless.none.stash
280
282
  };
281
283
  }
282
284
 
@@ -422,8 +424,7 @@ function makeOutboundRegisteredHandler(entry, sliceName, consumedEventSchema, ca
422
424
  },
423
425
  comp: comp,
424
426
  name: sliceName,
425
- tick: undefined,
426
- reconcile: undefined
427
+ tick: undefined
427
428
  };
428
429
  }
429
430
 
@@ -23,7 +23,7 @@ type sliceInfo = {
23
23
  queryDbResources: array<ReventlessInfra.Adapter.resource>,
24
24
  // Threaded to phase 1 collect/resolve on the automation path (mirrors the
25
25
  // in-process builder's `~context`); outbound slices take no context.
26
- context: option<Reventless.AutomationSlice.context>,
26
+ context?: Reventless.AutomationSlice.context,
27
27
  // The non-DCB topics this slice subscribes to — an Aggregate's EventTopic when
28
28
  // it names one by `Spec.name`. Empty for the common DCB-only slice.
29
29
  //
@@ -47,10 +47,10 @@ type sliceInfo = {
47
47
  // Resolved in the finalizer rather than here: an Aggregate's CommandTopic is
48
48
  // created *after* the slices that target it, so a lookup at registration time
49
49
  // finds nothing. Only the name is knowable this early.
50
- commandTargetName: option<string>,
50
+ commandTargetName?: string,
51
51
  // The automation's declared time; what the deploy's reconcile puts on the
52
52
  // platform, and what re-runs it when it changes.
53
- schedule: option<Reventless.Schedule.time>,
53
+ schedule?: Reventless.Schedule.time,
54
54
  // The schedules store's table, empty for a slice that maps no `Clock`. Granted to
55
55
  // the Lambda with the to-do tables, and named in the slice's handler config.
56
56
  schedulesResources: array<ReventlessInfra.Adapter.resource>,
@@ -116,11 +116,11 @@ let registerAutomationSlice = (
116
116
  callbackType,
117
117
  queryDbTableName,
118
118
  queryDbResources,
119
- context,
119
+ ?context,
120
120
  sourceTopics,
121
121
  consumesDcbLog,
122
- commandTargetName,
123
- schedule,
122
+ ?commandTargetName,
123
+ ?schedule,
124
124
  schedulesResources,
125
125
  capabilityNeeds,
126
126
  },
@@ -45,7 +45,7 @@ type derivedScope = {
45
45
  crossPartitionTagKeys: array<string>,
46
46
  tagKeysByEventType: dict<array<string>>,
47
47
  /** `None` only for a Lambda hosting no StateChangeSlices, which never appends. */
48
- partitionTag: option<Reventless.DcbTag.derivedPartitionTag>,
48
+ partitionTag?: Reventless.DcbTag.derivedPartitionTag,
49
49
  /** Slice name -> its partition: the handler's entity id and each command's envelope id. */
50
50
  partitionTagBySlice: dict<Reventless.DcbTag.derivedPartitionTag>,
51
51
  }
@@ -55,7 +55,6 @@ let deriveScope = (specs: array<specModule>): derivedScope =>
55
55
  | [] => {
56
56
  crossPartitionTagKeys: [],
57
57
  tagKeysByEventType: Dict.make(),
58
- partitionTag: None,
59
58
  partitionTagBySlice: Dict.make(),
60
59
  }
61
60
  | _ =>
@@ -89,7 +88,7 @@ let deriveScope = (specs: array<specModule>): derivedScope =>
89
88
  {
90
89
  crossPartitionTagKeys: scope.crossPartitionTagKeys,
91
90
  tagKeysByEventType: scope.tagKeysByEventType,
92
- partitionTag: Some(boundary.partitionTag),
91
+ partitionTag: boundary.partitionTag,
93
92
  partitionTagBySlice,
94
93
  }
95
94
  }
@@ -257,6 +256,7 @@ type inboundCallback = {
257
256
  receive: (
258
257
  ReventlessInfra.CommandTopic.publishJsons,
259
258
  JSON.t,
259
+ ~capabilities: Reventless.Capabilities.t,
260
260
  ~caller: Reventless.Identity.t=?,
261
261
  ~door: ReventlessInfra.InboundTranslationSlice.door=?,
262
262
  ) => promise<ReventlessInfra.InboundTranslationSlice.receiveResult>,
@@ -265,7 +265,7 @@ type inboundCallback = {
265
265
  ~errorCode: string,
266
266
  string,
267
267
  ) => ReventlessInfra.InboundTranslationSlice.receiveResult,
268
- webhook: option<ReventlessCore.InboundTranslationSlice_Webhook.route>,
268
+ webhook?: ReventlessCore.InboundTranslationSlice_Webhook.route,
269
269
  auditLog: dict<ReventlessCore.InboundTranslationSlice_Callback.auditRow>,
270
270
  }
271
271
  @module(
@@ -324,9 +324,12 @@ let buildInboundReceiver = (
324
324
  ) => {
325
325
  let callback = makeInboundCallback(spec)(translation)
326
326
  async (args: JSON.t, identity: Nullable.t<Reventless.Identity.t>): JSON.t => {
327
+ // No capabilities in this Lambda: a slice declaring a need is refused at
328
+ // deploy, so `none` is what every slice reaching here expects.
327
329
  let result = await callback.receive(
328
330
  publishJsons,
329
331
  args,
332
+ ~capabilities=Reventless.Capabilities.none,
330
333
  ~caller=ReventlessCore.InboundTranslationSlice_Callback.doorCaller(identity),
331
334
  )
332
335
  await persistAudit(callback, auditQueryDbOps, result)
@@ -354,7 +357,15 @@ let buildWebhookSlice = (
354
357
  ->Option.map((route): ReventlessCore.InboundTranslationSlice_Webhook.slice => {
355
358
  route,
356
359
  receive: async (input, ~caller) =>
357
- await persisted(await callback.receive(publishJsons, input, ~caller, ~door=Webhook)),
360
+ await persisted(
361
+ await callback.receive(
362
+ publishJsons,
363
+ input,
364
+ ~capabilities=Reventless.Capabilities.none,
365
+ ~caller,
366
+ ~door=Webhook,
367
+ ),
368
+ ),
358
369
  refuse: async (~body, ~errorCode, error) =>
359
370
  await persisted(callback.refuse(~body, ~errorCode, error)),
360
371
  })
@@ -12,6 +12,7 @@ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_excep
12
12
  import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
13
13
  import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
14
14
  import * as QueryDb$ReventlessCore from "@reventlessdev/reventless-core/src/components/QueryDb/QueryDb.res.mjs";
15
+ import * as Capabilities$Reventless from "@reventlessdev/reventless-spec/src/semantic/Capabilities.res.mjs";
15
16
  import * as EffectLogger$ReventlessCore from "@reventlessdev/reventless-core/src/util/EffectLogger.res.mjs";
16
17
  import * as CommandTopic_Helpers$ReventlessCore from "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic_Helpers.res.mjs";
17
18
  import * as InboundTranslationSlice_Webhook$ReventlessCore from "@reventlessdev/reventless-core/src/components/InboundTranslationSlice/InboundTranslationSlice_Webhook.res.mjs";
@@ -26,7 +27,6 @@ function deriveScope(specs) {
26
27
  return {
27
28
  crossPartitionTagKeys: [],
28
29
  tagKeysByEventType: {},
29
- partitionTag: undefined,
30
30
  partitionTagBySlice: {}
31
31
  };
32
32
  }
@@ -147,7 +147,7 @@ async function persistAudit(callback, auditQueryDbOps, result) {
147
147
  function buildInboundReceiver(spec, translation, publishJsons, auditQueryDbOps) {
148
148
  let callback = InboundTranslationSlice_CallbackResMjs.Make(spec)(translation);
149
149
  return async (args, identity) => {
150
- let result = await callback.receive(publishJsons, args, InboundTranslationSlice_Callback$ReventlessCore.doorCaller(identity), undefined);
150
+ let result = await callback.receive(publishJsons, args, Capabilities$Reventless.none, InboundTranslationSlice_Callback$ReventlessCore.doorCaller(identity), undefined);
151
151
  await persistAudit(callback, auditQueryDbOps, result);
152
152
  return CommandTopic_Helpers$ReventlessCore.commandOutcomeToJson(InboundTranslationSlice_Callback$ReventlessCore.receiveResultToOutcome(result));
153
153
  };
@@ -161,7 +161,7 @@ function buildWebhookSlice(spec, translation, publishJsons, auditQueryDbOps) {
161
161
  };
162
162
  return Stdlib_Nullable.fromOption(Stdlib_Option.map(callback.webhook, route => ({
163
163
  route: route,
164
- receive: async (input, caller) => await persisted(await callback.receive(publishJsons, input, caller, "Webhook")),
164
+ receive: async (input, caller) => await persisted(await callback.receive(publishJsons, input, Capabilities$Reventless.none, caller, "Webhook")),
165
165
  refuse: async (body, errorCode, error) => await persisted(callback.refuse(body, errorCode, error))
166
166
  })));
167
167
  }