@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
@@ -334,8 +334,7 @@ function MakeWithConfig(Config) {
334
334
  };
335
335
  domainEventsApiOpt = {
336
336
  name: "DomainEventsApi",
337
- api: api$2,
338
- defaultNamespace: undefined
337
+ api: api$2
339
338
  };
340
339
  } else {
341
340
  let cognitoPool = Platform_Stack$ReventlessAws.resolveCognitoUserPool();
@@ -1505,6 +1504,8 @@ function MakeWithConfig(Config) {
1505
1504
  return `\n Messaging is \`Capability_Messaging.make\`, passed to the platform as \`~messagingSender\`. The sender itself is configuration and has no default: set \`platform:messagingEmailSender\` in Pulumi.<stack>.yaml (or REVENTLESS_MESSAGING_EMAIL_SENDER), then verify the address with SES — or \`platform:messagingEmailProvider: log\` to log every message and send none.`;
1506
1505
  case "IdentityProvider" :
1507
1506
  return `\n IdentityProvider is the platform's Cognito pool, exported as \`identityProviderId\`. This platform stack exports none — deploy it first.`;
1507
+ case "Stash" :
1508
+ return `\n Stash has no deployed backend yet; the local platform keeps one in memory. Host a plugin that needs it on the local platform.`;
1508
1509
  }
1509
1510
  }))).join(""));
1510
1511
  }
@@ -1768,8 +1769,7 @@ function Make($star) {
1768
1769
  };
1769
1770
  domainEventsApiOpt = {
1770
1771
  name: "DomainEventsApi",
1771
- api: api$2,
1772
- defaultNamespace: undefined
1772
+ api: api$2
1773
1773
  };
1774
1774
  } else {
1775
1775
  let cognitoPool = Platform_Stack$ReventlessAws.resolveCognitoUserPool();
@@ -2914,6 +2914,8 @@ function Make($star) {
2914
2914
  return `\n Messaging is \`Capability_Messaging.make\`, passed to the platform as \`~messagingSender\`. The sender itself is configuration and has no default: set \`platform:messagingEmailSender\` in Pulumi.<stack>.yaml (or REVENTLESS_MESSAGING_EMAIL_SENDER), then verify the address with SES — or \`platform:messagingEmailProvider: log\` to log every message and send none.`;
2915
2915
  case "IdentityProvider" :
2916
2916
  return `\n IdentityProvider is the platform's Cognito pool, exported as \`identityProviderId\`. This platform stack exports none — deploy it first.`;
2917
+ case "Stash" :
2918
+ return `\n Stash has no deployed backend yet; the local platform keeps one in memory. Host a plugin that needs it on the local platform.`;
2917
2919
  }
2918
2920
  }))).join(""));
2919
2921
  }
@@ -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
 
@@ -64,7 +64,7 @@ let make = (
64
64
  ~id=name ++ "Policy",
65
65
  ~statements=[
66
66
  {
67
- sid: "AllowLambdaLogging",
67
+ PolicyDocument.sid: "AllowLambdaLogging",
68
68
  effect: Allow,
69
69
  actions: Actions([
70
70
  "logs:CreateLogGroup",
@@ -79,13 +79,20 @@ let make = (
79
79
  actions: Action("dynamodb:GetItem"),
80
80
  resources: Resource(tableArn),
81
81
  },
82
- {
83
- sid: "AllowReadingDomainId",
84
- effect: Allow,
85
- actions: Action("dynamodb:GetItem"),
86
- resources: Resource(identityArn),
87
- },
88
- ],
82
+ ]->Array.concat(
83
+ // A supplied pool with no identity store yet: nothing to read, and
84
+ // an empty resource would make the policy invalid.
85
+ identityArn == ""
86
+ ? []
87
+ : [
88
+ {
89
+ sid: "AllowReadingDomainId",
90
+ effect: Allow,
91
+ actions: Action("dynamodb:GetItem"),
92
+ resources: Resource(identityArn),
93
+ },
94
+ ],
95
+ ),
89
96
  )
90
97
  ->PolicyDocument.toJsonString
91
98
  ->Pulumi.Input.make,
@@ -19,6 +19,7 @@ function make(activeRoleTableName, activeRoleTableArn, identityTableName, identi
19
19
  activeRoleTableArn,
20
20
  identityTableArn
21
21
  ]).apply(param => {
22
+ let identityArn = param[1];
22
23
  new (Aws.iam.RolePolicy)(name + "Policy", {
23
24
  policy: PolicyDocument$PulumiAws.toJsonString(PolicyDocument$PulumiAws.make(undefined, name + "Policy", [
24
25
  {
@@ -36,14 +37,13 @@ function make(activeRoleTableName, activeRoleTableArn, identityTableName, identi
36
37
  Effect: "Allow",
37
38
  Action: "dynamodb:GetItem",
38
39
  Resource: param[0]
39
- },
40
- {
41
- Sid: "AllowReadingDomainId",
42
- Effect: "Allow",
43
- Action: "dynamodb:GetItem",
44
- Resource: param[1]
45
40
  }
46
- ])),
41
+ ].concat(identityArn === "" ? [] : [{
42
+ Sid: "AllowReadingDomainId",
43
+ Effect: "Allow",
44
+ Action: "dynamodb:GetItem",
45
+ Resource: identityArn
46
+ }]))),
47
47
  role: lambdaRole.id
48
48
  }, opts$1);
49
49
  });
@@ -41,12 +41,51 @@ let makeTable = (
41
41
  {name: table.name, arn: table.arn}
42
42
  }
43
43
 
44
- /** The store a resolved provider calls for — created or looked up. */
44
+ let log = ReventlessCore.Logger.fromEnv()
45
+
46
+ /**
47
+ The [ProviderScoped] table if `provision-identity` has created it, else an empty
48
+ name and ARN.
49
+
50
+ 🚨 **Absent is a supported state, not a failed lookup** — unlike the active-role
51
+ store, which a supplied pool has always had. A pool provisioned before this store
52
+ existed has no table, and its deployments must keep deploying: the trigger then
53
+ adds no claim and every account keeps its `sub`, which is exactly what each one
54
+ did before. Running `provision-identity` again creates the table, and the next
55
+ deploy picks it up. A Pulumi `getTable` fails the whole program on a missing
56
+ table, so this asks DynamoDB directly.
57
+ */
58
+ let lookupTableIfPresent = (~tableName: string): storeTable => {
59
+ let arn = Pulumi.Output.make(tableName)->Pulumi.Output.flatMap(name =>
60
+ (
61
+ async () =>
62
+ try {
63
+ let out = await AwsSdk.DynamoDb_DynamoDb.DescribeTableCommand.make({
64
+ tableName: name,
65
+ })->AwsSdk.DynamoDb_DynamoDb.DescribeTableCommand.send
66
+ out.table->Option.flatMap(t => t.tableArn)->Option.getOr("")
67
+ } catch {
68
+ | exn if Util_AwsError.isNotFound(exn) =>
69
+ log.warn(
70
+ ~comp="IdentityStore",
71
+ `no identity store "${name}" on this provider — accounts keep their pool id. Run provision-identity to create it.`,
72
+ )
73
+ ""
74
+ }
75
+ )()->Pulumi.Output.fromPromise
76
+ )
77
+ {
78
+ name: arn->Pulumi.Output.apply(found => found == "" ? "" : tableName),
79
+ arn,
80
+ }
81
+ }
82
+
83
+ /** The store a resolved provider calls for — created, or looked up if present. */
45
84
  let resolveTable = (
46
85
  ~choice: Auth_ActiveRoleStore.storeChoice,
47
86
  ~opts: Pulumi.ComponentResource.options,
48
87
  ): storeTable =>
49
88
  switch choice {
50
89
  | StackScoped => makeTable(~opts)
51
- | ProviderScoped(tableName) => Auth_ActiveRoleStore.lookupTable(~tableName)
90
+ | ProviderScoped(tableName) => lookupTableIfPresent(~tableName)
52
91
  }
@@ -1,9 +1,16 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as Output$Pulumi from "@reventlessdev/rescript-pulumi-pulumi/src/Output.res.mjs";
4
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
+ import * as Pulumi from "@pulumi/pulumi";
6
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
7
+ import * as Logger$ReventlessCore from "@reventlessdev/reventless-core/src/util/Logger.res.mjs";
3
8
  import * as AWS_Tags$ReventlessAws from "../AWS_Tags.res.mjs";
9
+ import * as ClientDynamodb from "@aws-sdk/client-dynamodb";
10
+ import * as DynamoDb_DynamoDb$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/DynamoDb_DynamoDb.res.mjs";
4
11
  import * as Util_Pulumi$ReventlessCore from "@reventlessdev/reventless-core/src/util/Util_Pulumi.res.mjs";
12
+ import * as Util_AwsError$ReventlessAws from "../../util/Util_AwsError.res.mjs";
5
13
  import * as Util_DynamoDb$ReventlessAws from "../../util/Util_DynamoDb.res.mjs";
6
- import * as Auth_ActiveRoleStore$ReventlessAws from "./Auth_ActiveRoleStore.res.mjs";
7
14
  import * as Auth_IdentityStore_Schema$ReventlessAws from "./Auth_IdentityStore_Schema.res.mjs";
8
15
 
9
16
  function chooseStore(identityProviderId) {
@@ -30,17 +37,49 @@ function makeTable(nameOpt, opts) {
30
37
  };
31
38
  }
32
39
 
40
+ let log = Logger$ReventlessCore.fromEnv();
41
+
42
+ function lookupTableIfPresent(tableName) {
43
+ let arn = Output$Pulumi.flatMap(Pulumi.output(tableName), name => (async () => {
44
+ try {
45
+ let out = await DynamoDb_DynamoDb$AwsSdk.DescribeTableCommand.send(new ClientDynamodb.DescribeTableCommand({
46
+ TableName: name
47
+ }));
48
+ return Stdlib_Option.getOr(Stdlib_Option.flatMap(out.Table, t => t.TableArn), "");
49
+ } catch (raw_exn) {
50
+ let exn = Primitive_exceptions.internalToException(raw_exn);
51
+ if (Util_AwsError$ReventlessAws.isNotFound(exn)) {
52
+ log.warn("IdentityStore", undefined, `no identity store "` + name + `" on this provider — accounts keep their pool id. Run provision-identity to create it.`);
53
+ return "";
54
+ }
55
+ throw exn;
56
+ }
57
+ })());
58
+ return {
59
+ name: arn.apply(found => {
60
+ if (found === "") {
61
+ return "";
62
+ } else {
63
+ return tableName;
64
+ }
65
+ }),
66
+ arn: arn
67
+ };
68
+ }
69
+
33
70
  function resolveTable(choice, opts) {
34
71
  if (typeof choice !== "object") {
35
72
  return makeTable(undefined, opts);
36
73
  } else {
37
- return Auth_ActiveRoleStore$ReventlessAws.lookupTable(choice._0);
74
+ return lookupTableIfPresent(choice._0);
38
75
  }
39
76
  }
40
77
 
41
78
  export {
42
79
  chooseStore,
43
80
  makeTable,
81
+ log,
82
+ lookupTableIfPresent,
44
83
  resolveTable,
45
84
  }
46
- /* AWS_Tags-ReventlessAws Not a pure module */
85
+ /* log Not a pure module */
@@ -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 = {