@reventlessdev/reventless-aws 3.0.0-alpha.396 → 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 (87) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/package.json +8 -8
  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/Auth/Auth_ActiveRoleTrigger.res +15 -8
  22. package/src/adapter/Auth/Auth_ActiveRoleTrigger.res.mjs +7 -7
  23. package/src/adapter/Auth/Auth_IdentityStore.res +41 -2
  24. package/src/adapter/Auth/Auth_IdentityStore.res.mjs +42 -3
  25. package/src/adapter/DcbEventLog/DcbBackend.res +3 -3
  26. package/src/adapter/DcbEventLog/DcbBackend.res.mjs +1 -3
  27. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +11 -9
  28. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res.mjs +4 -6
  29. package/src/adapter/EventLog/EventLogBackend.res +3 -3
  30. package/src/adapter/EventLog/EventLogBackend.res.mjs +1 -3
  31. package/src/adapter/Geocoder/Geocoder_AwsLocation_Backend.res +1 -1
  32. package/src/adapter/QueryDb/PgQueryResolver_Lambda.res +5 -5
  33. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +2 -2
  34. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +2 -2
  35. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +32 -32
  36. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +4 -3
  37. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +6 -6
  38. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +16 -5
  39. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res.mjs +3 -3
  40. package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +5 -5
  41. package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +24 -18
  42. package/src/adapter/Runtime/ReadModelEntryPoint_Ops.res +16 -14
  43. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +2 -2
  44. package/src/adapter/Runtime/RuntimeExtensionEntryPoint_Ops.res +4 -4
  45. package/src/adapter/Runtime/SideEffectEntryPoint_Ops.res +4 -4
  46. package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +9 -9
  47. package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +11 -9
  48. package/src/components/Api/AppSync_Adapter.res +4 -4
  49. package/src/components/InboundTranslationSlice_Builder.res +19 -0
  50. package/src/components/InboundTranslationSlice_Builder.res.mjs +12 -2
  51. package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +4 -7
  52. package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res.mjs +1 -4
  53. package/src/plugin/runtime/PluginRuntime_Builder.res +17 -26
  54. package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +7 -22
  55. package/tests/AppSyncEventsSigner_OpsTest.res +1 -1
  56. package/tests/AppSync_AdapterTest.res +4 -4
  57. package/tests/AppSync_AdapterTest.res.mjs +4 -8
  58. package/tests/Auth_ActiveRoleStoreTest.res +1 -1
  59. package/tests/Auth_ActiveRoleTrigger_OpsTest.res +1 -1
  60. package/tests/AutomationSliceEntryPoint_OpsTest.res +0 -2
  61. package/tests/AutomationSliceEntryPoint_OpsTest.res.mjs +3 -6
  62. package/tests/BakeConvergenceTest.res +1 -8
  63. package/tests/BakeConvergenceTest.res.mjs +3 -23
  64. package/tests/BakeManifestTest.res +5 -10
  65. package/tests/BakeManifestTest.res.mjs +1 -6
  66. package/tests/CommandLineTest.res +3 -3
  67. package/tests/DeployAppTest.res +3 -4
  68. package/tests/DeployAppTest.res.mjs +6 -15
  69. package/tests/EpInboundTestSlice.res +1 -0
  70. package/tests/EpInboundTestSlice.res.mjs +3 -0
  71. package/tests/EventCollectorPluginDefinitionAssetTest.res +1 -2
  72. package/tests/EventCollectorPluginDefinitionAssetTest.res.mjs +11 -21
  73. package/tests/IdentityProvider_Cognito_BackendTest.res +0 -3
  74. package/tests/IdentityProvider_Cognito_BackendTest.res.mjs +0 -3
  75. package/tests/PgQueryResolver_LambdaTest.res +6 -10
  76. package/tests/PgQueryResolver_LambdaTest.res.mjs +4 -34
  77. package/tests/Platform_ProvidedGroupsTest.res +2 -2
  78. package/tests/Platform_ProvidedGroupsTest.res.mjs +1 -2
  79. package/tests/ProvisionAccountsTest.res +5 -10
  80. package/tests/ProvisionAccountsTest.res.mjs +0 -9
  81. package/tests/ProvisionAdminTest.res +4 -9
  82. package/tests/ProvisionAdminTest.res.mjs +0 -7
  83. package/tests/ProvisionIdentityTest.res +2 -4
  84. package/tests/ProvisionIdentityTest.res.mjs +0 -2
  85. package/tests/SideEffectEntryPoint_OpsTest.res +2 -2
  86. package/tests/Util_ShellConfigTest.res +3 -3
  87. package/tests/Util_ShellConfigTest.res.mjs +1 -2
@@ -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
  }
@@ -106,7 +106,7 @@ type handlerConfig = {
106
106
  schedulerQueueArn: string,
107
107
  schedulerQueueName: string,
108
108
  extensionPoints: array<extensionPointConfig>,
109
- connectExtension: option<connectExtensionConfig>,
109
+ connectExtension?: connectExtensionConfig,
110
110
  extensions: array<extensionConfig>,
111
111
  readModelNamesForSourceName: dict<array<string>>,
112
112
  }
@@ -234,7 +234,7 @@ let parseHandlerConfig = (rawJson: string): handlerConfig => {
234
234
  schedulerQueueArn: obj->strOf("schedulerQueueArn")->Option.getOr(""),
235
235
  schedulerQueueName: obj->strOf("schedulerQueueName")->Option.getOr(""),
236
236
  extensionPoints,
237
- connectExtension,
237
+ ?connectExtension,
238
238
  extensions,
239
239
  readModelNamesForSourceName,
240
240
  }
@@ -253,7 +253,7 @@ type pluginProjection = {
253
253
  eventCollector: string,
254
254
  extensions: array<Reventless.Plugin.extensionDefinition>,
255
255
  extensionPoints: array<Reventless.Plugin.extensionPointDefinition>,
256
- dcbEventLog: option<Reventless.Plugin.dcbEventLogDefinition>,
256
+ dcbEventLog?: Reventless.Plugin.dcbEventLogDefinition,
257
257
  }
258
258
 
259
259
  let projectPluginRow = (row: JSON.t): option<pluginProjection> =>
@@ -323,7 +323,7 @@ let projectPluginRow = (row: JSON.t): option<pluginProjection> =>
323
323
  eventCollector: obj->strOf("eventCollector")->Option.getOr(""),
324
324
  extensions,
325
325
  extensionPoints,
326
- dcbEventLog,
326
+ ?dcbEventLog,
327
327
  })
328
328
  | _ => None
329
329
  }
@@ -339,7 +339,7 @@ let projectionOfDefinition = (d: Reventless.Plugin.pluginDefinition): pluginProj
339
339
  eventCollector: d.eventCollector,
340
340
  extensions: d.extensions,
341
341
  extensionPoints: d.extensionPoints,
342
- dcbEventLog: d.dcbEventLog->jsOption,
342
+ dcbEventLog: ?(d.dcbEventLog->jsOption),
343
343
  }
344
344
 
345
345
  // ── Cross-plugin SNS subscription manager ───────────────────────────────────
@@ -26,7 +26,7 @@ type handlerEntry = {
26
26
  }
27
27
 
28
28
  type resolverConfig = {
29
- pgConnection: option<PgConnection.connectionConfig>,
29
+ pgConnection?: PgConnection.connectionConfig,
30
30
  handlers: array<handlerEntry>,
31
31
  nodeTypes: dict<string>,
32
32
  }
@@ -59,10 +59,12 @@ let parseResolverConfig = (rawJson: string): resolverConfig => {
59
59
  ->JSON.Decode.object
60
60
  ->Option.getOr(Dict.make())
61
61
  {
62
- pgConnection: obj
63
- ->Dict.get("pgConnection")
64
- ->Option.filter(j => j != JSON.Null)
65
- ->Option.map(asPgConnection),
62
+ pgConnection: ?(
63
+ obj
64
+ ->Dict.get("pgConnection")
65
+ ->Option.filter(j => j != JSON.Null)
66
+ ->Option.map(asPgConnection)
67
+ ),
66
68
  handlers: obj
67
69
  ->Dict.get("handlers")
68
70
  ->Option.flatMap(JSON.Decode.array)
@@ -118,8 +120,8 @@ let makePushdowns = (
118
120
  // Reventless.Authorization.isAllowed matches on.
119
121
 
120
122
  type specInfo = {
121
- config: option<ProjectionEntryPoint_Ops.specConfig>,
122
- subIdConfig: option<Reventless.ReadModel.subIdConfig<JSON.t>>,
123
+ config?: ProjectionEntryPoint_Ops.specConfig,
124
+ subIdConfig?: Reventless.ReadModel.subIdConfig<JSON.t>,
123
125
  stateSchema: S.t<unknown>,
124
126
  authorization: Reventless.Authorization.permission,
125
127
  }
@@ -143,7 +145,7 @@ let registerBinding = (
143
145
  ),
144
146
  pushdowns,
145
147
  indexes,
146
- subIdField,
148
+ ?subIdField,
147
149
  capability: ReventlessCore.GraphQL_FragmentGenerator.deriveServerCapability(
148
150
  ~entityName=entry.readModelName,
149
151
  spec.stateSchema,
@@ -153,24 +155,28 @@ let registerBinding = (
153
155
  authorization: spec.authorization->Reventless.Authorization.named,
154
156
  // From the same schema `capability` is derived from, one line above, so the
155
157
  // two cannot end up disagreeing about this read model's fields.
156
- ownerField: Reventless.Owner.fieldNames(spec.stateSchema)->Array.get(0),
157
- retiredField: spec.stateSchema
158
- ->Reventless.StateAnnotations.getSpec
159
- ->Option.flatMap(a => a.retired)
160
- ->Option.map(r => r.field),
158
+ ownerField: ?(Reventless.Owner.fieldNames(spec.stateSchema)->Array.get(0)),
159
+ retiredField: ?(
160
+ spec.stateSchema
161
+ ->Reventless.StateAnnotations.getSpec
162
+ ->Option.flatMap(a => a.retired)
163
+ ->Option.map(r => r.field)
164
+ ),
161
165
  // The state form's other half. Carried beside the field rather than
162
166
  // re-derived at predicate time, so one place decides which rows are retired.
163
- retiredValues: spec.stateSchema
164
- ->Reventless.StateAnnotations.getSpec
165
- ->Option.flatMap(a => a.retired)
166
- ->Option.flatMap(r => r.values),
167
+ retiredValues: ?(
168
+ spec.stateSchema
169
+ ->Reventless.StateAnnotations.getSpec
170
+ ->Option.flatMap(a => a.retired)
171
+ ->Option.flatMap(r => r.values)
172
+ ),
167
173
  // Read off the retirement rather than from a second annotation: a record
168
174
  // cannot declare the reach of a retirement it does not have.
169
175
  namedWhenRetired: spec.stateSchema
170
176
  ->Reventless.StateAnnotations.getSpec
171
177
  ->Option.flatMap(a => a.retired)
172
178
  ->Option.mapOr(false, r => r.namedWhenRetired),
173
- imageSource: spec.stateSchema->Reventless.RowImage.sourceFrom,
179
+ imageSource: ?(spec.stateSchema->Reventless.RowImage.sourceFrom),
174
180
  },
175
181
  )
176
182
  logDebug("registered resolver binding for " ++ entry.readModelName, {comp: "PgQueryResolver"})
@@ -22,10 +22,10 @@ type handlerEntry = {
22
22
  // ReScript dispatch boundary's `EventCollector(<Name>)` byte for byte. This
23
23
  // Lambda hosts every read model, so the comp is what separates their log
24
24
  // lines; the plugin beats the Lambda-name-derived fallback in runEffect.
25
- comp: option<string>,
26
- plugin: option<string>,
27
- pgConnection: option<PgConnection.connectionConfig>,
28
- stateTopicName: option<string>,
25
+ comp?: string,
26
+ plugin?: string,
27
+ pgConnection?: PgConnection.connectionConfig,
28
+ stateTopicName?: string,
29
29
  }
30
30
 
31
31
  // The builder writes `pgConnection` via PgConnection.connectionConfigToJson, so
@@ -44,13 +44,15 @@ let decodeEntry = (json: JSON.t): option<handlerEntry> =>
44
44
  mappingsModule: h->strOf("mappingsModule")->Option.getOr(""),
45
45
  queryDbTableName: h->strOf("queryDbTableName")->Option.getOr(""),
46
46
  sourceUrn: h->strOf("sourceUrn")->Option.getOr(""),
47
- comp: h->strOf("comp"),
48
- plugin: h->strOf("plugin"),
49
- pgConnection: h
50
- ->Dict.get("pgConnection")
51
- ->Option.filter(j => j != JSON.Null)
52
- ->Option.map(asPgConnection),
53
- stateTopicName: h->strOf("stateTopicName"),
47
+ comp: ?(h->strOf("comp")),
48
+ plugin: ?(h->strOf("plugin")),
49
+ pgConnection: ?(
50
+ h
51
+ ->Dict.get("pgConnection")
52
+ ->Option.filter(j => j != JSON.Null)
53
+ ->Option.map(asPgConnection)
54
+ ),
55
+ stateTopicName: ?(h->strOf("stateTopicName")),
54
56
  })
55
57
 
56
58
  let parseHandlerConfig = (rawJson: string): array<handlerEntry> =>
@@ -88,10 +90,10 @@ let withInjectedId = (
88
90
  }
89
91
 
90
92
  type specInfo = {
91
- config: option<ProjectionEntryPoint_Ops.specConfig>,
92
- subIdConfig: option<Reventless.ReadModel.subIdConfig<JSON.t>>,
93
+ config?: ProjectionEntryPoint_Ops.specConfig,
94
+ subIdConfig?: Reventless.ReadModel.subIdConfig<JSON.t>,
93
95
  // Read off the runtime-loaded spec module; `None` on a module that predates it.
94
- stateSchema: option<S.t<unknown>>,
96
+ stateSchema?: S.t<unknown>,
95
97
  }
96
98
 
97
99
  let buildOperations = (
@@ -269,8 +269,8 @@ let makeFromCodeAsset: (
269
269
  // registered — an extension-free deployment gets the env it always had.
270
270
  if !ReventlessCore.RuntimeExtension.isEmpty() {
271
271
  let {
272
- ReventlessCore.ResourceAttribution.plugin: plugin,
273
- platform,
272
+ ReventlessCore.ResourceAttribution.plugin: ?plugin,
273
+ ?platform,
274
274
  } = ReventlessCore.ResourceAttribution.current.contents
275
275
  let orNull = o => o->Option.mapOr(JSON.Null, s => JSON.String(s))
276
276
  let config = JSON.Object(
@@ -29,8 +29,8 @@ type config = {
29
29
  modules: array<string>,
30
30
  runtimeKind: string,
31
31
  component: string,
32
- plugin: option<string>,
33
- platform: option<string>,
32
+ plugin?: string,
33
+ platform?: string,
34
34
  }
35
35
 
36
36
  let decodeString = (obj: dict<JSON.t>, key: string): option<string> =>
@@ -70,8 +70,8 @@ let parseConfig = (raw: option<string>): option<config> =>
70
70
  modules,
71
71
  runtimeKind,
72
72
  component,
73
- plugin: obj->decodeString("plugin"),
74
- platform: obj->decodeString("platform"),
73
+ plugin: ?(obj->decodeString("plugin")),
74
+ platform: ?(obj->decodeString("platform")),
75
75
  })
76
76
  | _ =>
77
77
  log.error(
@@ -14,8 +14,8 @@ type handlerEntry = {
14
14
  // Resolved at deploy time and baked into HANDLER_CONFIG
15
15
  // (SideEffectHandlerRuntime_Builder_Single) — the shell has only module paths
16
16
  // to identify a handler by.
17
- comp: option<string>,
18
- plugin: option<string>,
17
+ comp?: string,
18
+ plugin?: string,
19
19
  }
20
20
 
21
21
  let strOf = (obj: dict<JSON.t>, key: string): option<string> =>
@@ -31,8 +31,8 @@ let decodeEntry = (json: JSON.t): option<handlerEntry> =>
31
31
  ->Option.flatMap(JSON.Decode.array)
32
32
  ->Option.getOr([])
33
33
  ->Array.filterMap(JSON.Decode.string),
34
- comp: h->strOf("comp"),
35
- plugin: h->strOf("plugin"),
34
+ comp: ?(h->strOf("comp")),
35
+ plugin: ?(h->strOf("plugin")),
36
36
  })
37
37
 
38
38
  let parseHandlerConfig = (rawJson: string): array<handlerEntry> =>
@@ -17,8 +17,8 @@ type handlerEntry = {
17
17
  sourceUrn: string,
18
18
  // B3.3: per-slice AppSync Events channel root (list field name). Present only
19
19
  // for subscription-enabled (Stream) Postgres view slices.
20
- stateTopicName: option<string>,
21
- pgConnection: option<PgConnection.connectionConfig>,
20
+ stateTopicName?: string,
21
+ pgConnection?: PgConnection.connectionConfig,
22
22
  }
23
23
 
24
24
  // The builder writes `pgConnection` via PgConnection.connectionConfigToJson, so
@@ -67,16 +67,16 @@ let parseHandlerConfig = (rawJson: string): array<handlerEntry> =>
67
67
  projectionModule: h->strOf("projectionModule")->Option.getOr(""),
68
68
  queryDbTableName: h->strOf("queryDbTableName")->Option.getOr(""),
69
69
  sourceUrn: h->strOf("sourceUrn")->Option.getOr(""),
70
- stateTopicName: h->strOf("stateTopicName"),
71
- pgConnection: h->pgConnectionOf,
70
+ stateTopicName: ?(h->strOf("stateTopicName")),
71
+ pgConnection: ?(h->pgConnectionOf),
72
72
  }
73
73
  | None => {
74
74
  specModule: base ++ h->strOf("s")->Option.getOr(""),
75
75
  projectionModule: base ++ h->strOf("p")->Option.getOr(""),
76
76
  queryDbTableName: h->strOf("q")->Option.getOr(""),
77
77
  sourceUrn: h->strOf("u")->Option.getOr(sharedUrn),
78
- stateTopicName: h->strOf("t"),
79
- pgConnection: sharedPgConnection,
78
+ stateTopicName: ?(h->strOf("t")),
79
+ pgConnection: ?sharedPgConnection,
80
80
  }
81
81
  }
82
82
  )
@@ -197,10 +197,10 @@ type sliceModules<'event> = {
197
197
  project: Reventless.StateViewSlice.consumed<'event> => array<
198
198
  Reventless.Projection.action<string, JSON.t>,
199
199
  >,
200
- config: option<ProjectionEntryPoint_Ops.specConfig>,
201
- subIdConfig: option<Reventless.ReadModel.subIdConfig<JSON.t>>,
200
+ config?: ProjectionEntryPoint_Ops.specConfig,
201
+ subIdConfig?: Reventless.ReadModel.subIdConfig<JSON.t>,
202
202
  // Same union stamp the read-model path needs; a slice's state can hold one too.
203
- stateSchema: option<S.t<unknown>>,
203
+ stateSchema?: S.t<unknown>,
204
204
  }
205
205
 
206
206
  let makeRegisteredHandler = (
@@ -24,7 +24,7 @@ type handlerConfig = {
24
24
  callbackModule: string,
25
25
  // aggregateName → env-var name holding the aggregate's cmd-topic SQS URL.
26
26
  publishToAggregates: dict<string>,
27
- scheduler: option<schedulerEnvConfig>,
27
+ scheduler?: schedulerEnvConfig,
28
28
  }
29
29
 
30
30
  let strOf = (obj: dict<JSON.t>, key: string): option<string> =>
@@ -45,14 +45,16 @@ let parseHandlerConfig = (rawJson: string): handlerConfig => {
45
45
  ->Dict.toArray
46
46
  ->Array.filterMap(((k, v)) => v->JSON.Decode.string->Option.map(s => (k, s)))
47
47
  ->Dict.fromArray,
48
- scheduler: obj
49
- ->Dict.get("scheduler")
50
- ->Option.flatMap(JSON.Decode.object)
51
- ->Option.map(s => {
52
- roleArnEnv: s->strOf("roleArnEnv")->Option.getOr(""),
53
- targetArnEnv: s->strOf("targetArnEnv")->Option.getOr(""),
54
- targetNameEnv: s->strOf("targetNameEnv")->Option.getOr(""),
55
- }),
48
+ scheduler: ?(
49
+ obj
50
+ ->Dict.get("scheduler")
51
+ ->Option.flatMap(JSON.Decode.object)
52
+ ->Option.map(s => {
53
+ roleArnEnv: s->strOf("roleArnEnv")->Option.getOr(""),
54
+ targetArnEnv: s->strOf("targetArnEnv")->Option.getOr(""),
55
+ targetNameEnv: s->strOf("targetNameEnv")->Option.getOr(""),
56
+ })
57
+ ),
56
58
  }
57
59
  }
58
60
 
@@ -68,7 +68,7 @@ let startSchemaCreationRetrying = (client: appSyncClient, input: startSchemaCrea
68
68
  // GetSchemaCreationStatus — poll until schema is ACTIVE
69
69
  type getSchemaCreationStatusInput = {apiId: string}
70
70
  type getSchemaCreationStatusCommand
71
- type getSchemaCreationStatusResult = {status: string, details: option<string>}
71
+ type getSchemaCreationStatusResult = {status: string, details?: string}
72
72
 
73
73
  @module("@aws-sdk/client-appsync") @new
74
74
  external makeGetSchemaCreationStatusCommand: getSchemaCreationStatusInput => getSchemaCreationStatusCommand =
@@ -119,10 +119,10 @@ type getSourceApiAssociationInput = {
119
119
  }
120
120
  type getSourceApiAssociationCommand
121
121
  type sourceApiAssociationSummary = {
122
- sourceApiAssociationStatus: option<string>,
123
- sourceApiAssociationStatusDetail: option<string>,
122
+ sourceApiAssociationStatus?: string,
123
+ sourceApiAssociationStatusDetail?: string,
124
124
  }
125
- type getSourceApiAssociationResult = {sourceApiAssociation: option<sourceApiAssociationSummary>}
125
+ type getSourceApiAssociationResult = {sourceApiAssociation?: sourceApiAssociationSummary}
126
126
 
127
127
  @module("@aws-sdk/client-appsync") @new
128
128
  external makeGetSourceApiAssociationCommand: getSourceApiAssociationInput => getSourceApiAssociationCommand =