@reventlessdev/reventless-aws 3.0.0-alpha.263 → 3.0.0-alpha.265
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.
- package/CHANGELOG.md +17 -0
- package/package.json +7 -7
- package/src/Platform.res +37 -6
- package/src/Platform.res.mjs +21 -6
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res +6 -1
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res.mjs +4 -1
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res +5 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res.mjs +3 -0
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res +6 -1
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res.mjs +4 -1
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res +6 -1
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res.mjs +4 -1
- package/src/adapter/CommandTopic/CommandTopicRegistry.res +50 -0
- package/src/adapter/CommandTopic/CommandTopicRegistry.res.mjs +26 -0
- package/src/adapter/Runtime/AutomationSliceEntryPoint.mjs +21 -3
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +230 -29
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +124 -9
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +188 -3
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res.mjs +107 -6
- package/src/components/AutomationSlice_Builder.res.mjs +1 -1
- package/src/components/OutboundTranslationSlice_Builder.res +20 -0
- package/src/components/OutboundTranslationSlice_Builder.res.mjs +12 -2
- package/src/plugin/runtime/PluginRuntime_Builder.res +26 -0
- package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +26 -0
- package/tests/AutomationSliceEntryPoint_OpsTest.res +44 -3
- package/tests/AutomationSliceEntryPoint_OpsTest.res.mjs +65 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.265 (2026-08-04)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **aws:** make a slice's TODO backlog survive, and actually sweep it ([f35dcbd](https://github.com/ReventlessDev/reventless-core/commit/f35dcbd86374124106c2d1e48d29c6f41fdbec2c))
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **outbound:** hand translate its geocoder instead of making it fetch one ([fb18312](https://github.com/ReventlessDev/reventless-core/commit/fb1831216b37c9562868c46e1a09054e69418c67))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# 3.0.0-alpha.264 (2026-08-03)
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **aws:** give slice command publishes a queue they can actually reach ([42fdb55](https://github.com/ReventlessDev/reventless-core/commit/42fdb55b751a197d586c49e3615ce12ffea42046))
|
|
21
|
+
|
|
22
|
+
|
|
6
23
|
# 3.0.0-alpha.263 (2026-08-03)
|
|
7
24
|
|
|
8
25
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-aws",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.265",
|
|
4
4
|
"description": "AWS adapters for Reventless",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"dependencies": {
|
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
17
17
|
"@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.65",
|
|
18
18
|
"@reventlessdev/rescript-node": "2.0.0-alpha.1",
|
|
19
|
-
"@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
|
|
20
19
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.18",
|
|
21
|
-
"@reventlessdev/
|
|
22
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.
|
|
23
|
-
"@reventlessdev/reventless-
|
|
24
|
-
"@reventlessdev/reventless-
|
|
25
|
-
"@reventlessdev/reventless-
|
|
20
|
+
"@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
|
|
21
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.210",
|
|
22
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.125",
|
|
23
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.74",
|
|
24
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.100",
|
|
25
|
+
"@reventlessdev/reventless-interop": "3.0.0-alpha.30"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"rescript": "12.3.0",
|
package/src/Platform.res
CHANGED
|
@@ -96,6 +96,12 @@ let getObjectStoreEndpoints = () => objectStoreEndpointsRef.contents
|
|
|
96
96
|
the same sentinel, as `PluginRuntime_Builder.inboundSliceReg.auditTableName`. */
|
|
97
97
|
let geocoderEndpointRef: ref<Pulumi.Output.t<string>> = ref(Pulumi.Output.make(""))
|
|
98
98
|
|
|
99
|
+
/** The geocoding place index, for the monolithic case — the SDK-side half of the
|
|
100
|
+
same capability, carried for exactly the reasons above and with the same `""`
|
|
101
|
+
sentinel. Slice Lambdas call Amazon Location directly with this; only the
|
|
102
|
+
browser needs the Function URL. */
|
|
103
|
+
let geocoderPlaceIndexRef: ref<Pulumi.Output.t<string>> = ref(Pulumi.Output.make(""))
|
|
104
|
+
|
|
99
105
|
module MakeWithConfig = (
|
|
100
106
|
Config: {
|
|
101
107
|
let splitApi: bool
|
|
@@ -794,12 +800,17 @@ module MakeWithConfig = (
|
|
|
794
800
|
let tableResource = outputs.resources->Array.getUnsafe(0)
|
|
795
801
|
PluginRuntime_Builder.registerDcbTableName(tableResource.name)
|
|
796
802
|
},
|
|
797
|
-
// DCB CommandTopic created hook — extracts SQS queue URL for slice builders
|
|
803
|
+
// DCB CommandTopic created hook — extracts SQS queue URL for slice builders,
|
|
804
|
+
// and the queue resource so the slice Lambda's role is granted
|
|
805
|
+
// `sqs:SendMessage` on it.
|
|
798
806
|
onDcbCommandTopicCreated: dcbCommandTopicUnknown => {
|
|
799
807
|
let commandTopic = dcbCommandTopicUnknown->asDcbCommandTopicComponent
|
|
800
808
|
let channel = commandTopic->ReventlessCore.CommandTopic_Adapter.channel
|
|
801
809
|
let channelParts = channel.parts->asSqsChannelParts
|
|
802
|
-
AutomationSliceRuntime_Builder_Single.setDcbQueueUrl(
|
|
810
|
+
AutomationSliceRuntime_Builder_Single.setDcbQueueUrl(
|
|
811
|
+
~resource=?channel.resources->Array.get(0),
|
|
812
|
+
channelParts.queue.id,
|
|
813
|
+
)
|
|
803
814
|
},
|
|
804
815
|
// DCB slices created hook — finalize slice Lambdas.
|
|
805
816
|
onDcbSlicesCreated: dcbEventLogUnknown => {
|
|
@@ -2078,6 +2089,19 @@ module MakeWithConfig = (
|
|
|
2078
2089
|
Pulumi.Pulumi.export("geocoderEndpoint", geocoderEndpointFlat)
|
|
2079
2090
|
geocoderEndpointRef := geocoderEndpointFlat
|
|
2080
2091
|
|
|
2092
|
+
// The place index itself, exported beside the Function URL because the two
|
|
2093
|
+
// callers need different things from the same capability. A browser cannot
|
|
2094
|
+
// sign an SDK call and gets the URL; a slice's Lambda can, and gets the
|
|
2095
|
+
// index name — no proxy hop, and no dependence on a public unauthenticated
|
|
2096
|
+
// endpoint for an unattended path. `""` when unset, for the same
|
|
2097
|
+
// one-shape-to-handle reason as the endpoint above.
|
|
2098
|
+
let geocoderPlaceIndexFlat = switch cfg.geocoderPlaceIndex {
|
|
2099
|
+
| Some(index) => index.indexName->Pulumi.Output.fromInput
|
|
2100
|
+
| None => Pulumi.Output.make("")
|
|
2101
|
+
}
|
|
2102
|
+
Pulumi.Pulumi.export("geocoderPlaceIndex", geocoderPlaceIndexFlat)
|
|
2103
|
+
geocoderPlaceIndexRef := geocoderPlaceIndexFlat
|
|
2104
|
+
|
|
2081
2105
|
// Presign endpoints are no longer written to config.json: under route B the
|
|
2082
2106
|
// client calls the platform API's `Upload_Presign` mutation (reachable from
|
|
2083
2107
|
// `platformApiEndpoint`, already present) with the store it declares, so there
|
|
@@ -2246,15 +2270,22 @@ module MakeWithConfig = (
|
|
|
2246
2270
|
// is a modelled outcome, which is the point of the empty string: a plugin
|
|
2247
2271
|
// deployed against a platform without the capability degrades rather than
|
|
2248
2272
|
// failing to deploy.
|
|
2249
|
-
|
|
2273
|
+
// The place index, not the Function URL. A slice's Lambda reaches Amazon
|
|
2274
|
+
// Location through the SDK now, so what it needs is the index's name — and
|
|
2275
|
+
// the grant that goes with it, which is why this is also handed to
|
|
2276
|
+
// `registerGeocoderPlaceIndex` rather than only to the environment. The
|
|
2277
|
+
// browser keeps using the Function URL until the platform API carries a
|
|
2278
|
+
// geocode field; the two doors are independent.
|
|
2279
|
+
let geocoderPlaceIndex: Pulumi.Output.t<string> = switch platformStackRef {
|
|
2250
2280
|
| Some(stackRef) =>
|
|
2251
2281
|
(
|
|
2252
|
-
stackRef->Pulumi.StackReference.getOutput("
|
|
2282
|
+
stackRef->Pulumi.StackReference.getOutput("geocoderPlaceIndex"):
|
|
2253
2283
|
Pulumi.Output.t<option<string>>
|
|
2254
2284
|
)->Pulumi.Output.apply(o => o->Option.getOr(""))
|
|
2255
|
-
| None =>
|
|
2285
|
+
| None => geocoderPlaceIndexRef.contents
|
|
2256
2286
|
}
|
|
2257
|
-
PluginRuntime_Builder.registerCapabilityEnv("
|
|
2287
|
+
PluginRuntime_Builder.registerCapabilityEnv("PLACE_INDEX_NAME", geocoderPlaceIndex)
|
|
2288
|
+
PluginRuntime_Builder.registerGeocoderPlaceIndex(geocoderPlaceIndex)
|
|
2258
2289
|
|
|
2259
2290
|
module P = unpack(plugin)
|
|
2260
2291
|
let pluginComponent = P.make()
|
package/src/Platform.res.mjs
CHANGED
|
@@ -134,6 +134,10 @@ let geocoderEndpointRef = {
|
|
|
134
134
|
contents: Pulumi.output("")
|
|
135
135
|
};
|
|
136
136
|
|
|
137
|
+
let geocoderPlaceIndexRef = {
|
|
138
|
+
contents: Pulumi.output("")
|
|
139
|
+
};
|
|
140
|
+
|
|
137
141
|
function MakeWithConfig(Config) {
|
|
138
142
|
Stdlib_Option.forEach(Config.commandHandlerConfig.aggregates, param => {
|
|
139
143
|
Stdlib_Option.forEach(param.sync, AggregateRuntime_Builder_Single$ReventlessAws.setConfig);
|
|
@@ -542,7 +546,7 @@ function MakeWithConfig(Config) {
|
|
|
542
546
|
let hooks_onDcbCommandTopicCreated = dcbCommandTopicUnknown => {
|
|
543
547
|
let channel = dcbCommandTopicUnknown.channel;
|
|
544
548
|
let channelParts = channel.parts;
|
|
545
|
-
AutomationSliceRuntime_Builder_Single$ReventlessAws.setDcbQueueUrl(channelParts.queue.id);
|
|
549
|
+
AutomationSliceRuntime_Builder_Single$ReventlessAws.setDcbQueueUrl(undefined, channel.resources[0], channelParts.queue.id);
|
|
546
550
|
};
|
|
547
551
|
let hooks_onDcbSlicesCreated = dcbEventLogUnknown => {
|
|
548
552
|
StateViewSliceRuntime_Builder_Single$ReventlessAws.finishWithDcbEventLog(dcbEventLogUnknown);
|
|
@@ -1131,6 +1135,10 @@ function MakeWithConfig(Config) {
|
|
|
1131
1135
|
let geocoderEndpointFlat = geocoderEndpointOutput.apply(o => Stdlib_Option.getOr(o, ""));
|
|
1132
1136
|
Pulumi$Pulumi.$$export("geocoderEndpoint", geocoderEndpointFlat);
|
|
1133
1137
|
geocoderEndpointRef.contents = geocoderEndpointFlat;
|
|
1138
|
+
let index$1 = hostUiBundle.geocoderPlaceIndex;
|
|
1139
|
+
let geocoderPlaceIndexFlat = index$1 !== undefined ? index$1.indexName : Pulumi.output("");
|
|
1140
|
+
Pulumi$Pulumi.$$export("geocoderPlaceIndex", geocoderPlaceIndexFlat);
|
|
1141
|
+
geocoderPlaceIndexRef.contents = geocoderPlaceIndexFlat;
|
|
1134
1142
|
let configJsonContent = Pulumi.all([
|
|
1135
1143
|
Pulumi.all([
|
|
1136
1144
|
resolvedDomainApiEndpoint,
|
|
@@ -1247,8 +1255,9 @@ function MakeWithConfig(Config) {
|
|
|
1247
1255
|
bytes: bytes.length
|
|
1248
1256
|
};
|
|
1249
1257
|
});
|
|
1250
|
-
let
|
|
1251
|
-
PluginRuntime_Builder$ReventlessAws.registerCapabilityEnv("
|
|
1258
|
+
let geocoderPlaceIndex = platformStackRef !== undefined ? Primitive_option.valFromOption(platformStackRef).getOutput("geocoderPlaceIndex").apply(o => Stdlib_Option.getOr(o, "")) : geocoderPlaceIndexRef.contents;
|
|
1259
|
+
PluginRuntime_Builder$ReventlessAws.registerCapabilityEnv("PLACE_INDEX_NAME", geocoderPlaceIndex);
|
|
1260
|
+
PluginRuntime_Builder$ReventlessAws.registerGeocoderPlaceIndex(geocoderPlaceIndex);
|
|
1252
1261
|
let pluginComponent = plugin.make();
|
|
1253
1262
|
Plugin_Helpers$ReventlessCore.clearOffload();
|
|
1254
1263
|
currentDeployTarget.contents = "Domain";
|
|
@@ -1796,7 +1805,7 @@ function Make($star) {
|
|
|
1796
1805
|
let hooks_onDcbCommandTopicCreated = dcbCommandTopicUnknown => {
|
|
1797
1806
|
let channel = dcbCommandTopicUnknown.channel;
|
|
1798
1807
|
let channelParts = channel.parts;
|
|
1799
|
-
AutomationSliceRuntime_Builder_Single$ReventlessAws.setDcbQueueUrl(channelParts.queue.id);
|
|
1808
|
+
AutomationSliceRuntime_Builder_Single$ReventlessAws.setDcbQueueUrl(undefined, channel.resources[0], channelParts.queue.id);
|
|
1800
1809
|
};
|
|
1801
1810
|
let hooks_onDcbSlicesCreated = dcbEventLogUnknown => {
|
|
1802
1811
|
StateViewSliceRuntime_Builder_Single$ReventlessAws.finishWithDcbEventLog(dcbEventLogUnknown);
|
|
@@ -2362,6 +2371,10 @@ function Make($star) {
|
|
|
2362
2371
|
let geocoderEndpointFlat = geocoderEndpointOutput.apply(o => Stdlib_Option.getOr(o, ""));
|
|
2363
2372
|
Pulumi$Pulumi.$$export("geocoderEndpoint", geocoderEndpointFlat);
|
|
2364
2373
|
geocoderEndpointRef.contents = geocoderEndpointFlat;
|
|
2374
|
+
let index$1 = hostUiBundle.geocoderPlaceIndex;
|
|
2375
|
+
let geocoderPlaceIndexFlat = index$1 !== undefined ? index$1.indexName : Pulumi.output("");
|
|
2376
|
+
Pulumi$Pulumi.$$export("geocoderPlaceIndex", geocoderPlaceIndexFlat);
|
|
2377
|
+
geocoderPlaceIndexRef.contents = geocoderPlaceIndexFlat;
|
|
2365
2378
|
let configJsonContent = Pulumi.all([
|
|
2366
2379
|
Pulumi.all([
|
|
2367
2380
|
resolvedDomainApiEndpoint,
|
|
@@ -2478,8 +2491,9 @@ function Make($star) {
|
|
|
2478
2491
|
bytes: bytes.length
|
|
2479
2492
|
};
|
|
2480
2493
|
});
|
|
2481
|
-
let
|
|
2482
|
-
PluginRuntime_Builder$ReventlessAws.registerCapabilityEnv("
|
|
2494
|
+
let geocoderPlaceIndex = platformStackRef !== undefined ? Primitive_option.valFromOption(platformStackRef).getOutput("geocoderPlaceIndex").apply(o => Stdlib_Option.getOr(o, "")) : geocoderPlaceIndexRef.contents;
|
|
2495
|
+
PluginRuntime_Builder$ReventlessAws.registerCapabilityEnv("PLACE_INDEX_NAME", geocoderPlaceIndex);
|
|
2496
|
+
PluginRuntime_Builder$ReventlessAws.registerGeocoderPlaceIndex(geocoderPlaceIndex);
|
|
2483
2497
|
let pluginComponent = plugin.make();
|
|
2484
2498
|
Plugin_Helpers$ReventlessCore.clearOffload();
|
|
2485
2499
|
currentDeployTarget.contents = "Domain";
|
|
@@ -2632,6 +2646,7 @@ export {
|
|
|
2632
2646
|
objectStoreEndpointsRef,
|
|
2633
2647
|
getObjectStoreEndpoints,
|
|
2634
2648
|
geocoderEndpointRef,
|
|
2649
|
+
geocoderPlaceIndexRef,
|
|
2635
2650
|
MakeWithConfig,
|
|
2636
2651
|
Make,
|
|
2637
2652
|
}
|
|
@@ -65,10 +65,15 @@ let make: ReventlessCore.CommandTopic_Adapter.channelMaker<
|
|
|
65
65
|
)
|
|
66
66
|
|
|
67
67
|
let resolvedQueueOutput = queue->Util_SQS.toResolvedQueueOutput
|
|
68
|
+
let queueResource = queue->Util_SQS.toResource(~tags=tags->Pulumi.Output.fromInput)
|
|
69
|
+
|
|
70
|
+
// Recorded while the queue is still concrete, so a component publishing to
|
|
71
|
+
// this owner from a Lambda can be given the URL and flavor as configuration.
|
|
72
|
+
CommandTopicRegistry.register(~owner, ~queueUrl=queue.id, ~resource=queueResource, ~isFifo=false)
|
|
68
73
|
|
|
69
74
|
{
|
|
70
75
|
ReventlessCore.CommandTopic_Adapter.parts: {queue: queue},
|
|
71
|
-
resources: [
|
|
76
|
+
resources: [queueResource],
|
|
72
77
|
publishJsons: resolvedQueueOutput->Pulumi.Output.apply(resolvedQueue =>
|
|
73
78
|
resolvedQueue->CommandTopicChannel_SQS_Runtime.publishJsons(AWS.SQS, ...)
|
|
74
79
|
),
|
|
@@ -12,6 +12,7 @@ import * as AWS_Tags$ReventlessAws from "../AWS_Tags.res.mjs";
|
|
|
12
12
|
import * as Util_SQS$ReventlessAws from "../../util/Util_SQS.res.mjs";
|
|
13
13
|
import * as Util_Pulumi$ReventlessCore from "@reventlessdev/reventless-core/src/util/Util_Pulumi.res.mjs";
|
|
14
14
|
import * as CommandTopic$ReventlessCore from "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic.res.mjs";
|
|
15
|
+
import * as CommandTopicRegistry$ReventlessAws from "./CommandTopicRegistry.res.mjs";
|
|
15
16
|
import * as Util_DeadLetterQueue$ReventlessAws from "../../util/Util_DeadLetterQueue.res.mjs";
|
|
16
17
|
import * as CommandTopicChannel_Helpers$ReventlessAws from "./CommandTopicChannel_Helpers.res.mjs";
|
|
17
18
|
import * as CommandTopicChannel_SQS_Runtime$ReventlessAws from "./CommandTopicChannel_SQS_Runtime.res.mjs";
|
|
@@ -48,11 +49,13 @@ function make(name, owner, opts) {
|
|
|
48
49
|
sqsManagedSseEnabled: false
|
|
49
50
|
}, opts$1 !== undefined ? Primitive_option.valFromOption(opts$1) : undefined);
|
|
50
51
|
let resolvedQueueOutput = Util_SQS$ReventlessAws.toResolvedQueueOutput(queue);
|
|
52
|
+
let queueResource = Util_SQS$ReventlessAws.toResource(tags, queue);
|
|
53
|
+
CommandTopicRegistry$ReventlessAws.register(owner, queue.id, queueResource, false);
|
|
51
54
|
return {
|
|
52
55
|
parts: {
|
|
53
56
|
queue: queue
|
|
54
57
|
},
|
|
55
|
-
resources: [
|
|
58
|
+
resources: [queueResource],
|
|
56
59
|
publishJsons: resolvedQueueOutput.apply(resolvedQueue => CommandTopicChannel_SQS_Runtime$ReventlessAws.publishJsons(resolvedQueue, "SQS")),
|
|
57
60
|
publishJsonsStream: resolvedQueueOutput.apply(resolvedQueue => {
|
|
58
61
|
let publishJsons = CommandTopicChannel_SQS_Runtime$ReventlessAws.publishJsons(resolvedQueue, "SQS");
|
|
@@ -44,6 +44,11 @@ let make: ReventlessCore.CommandTopic_Adapter.channelMaker<
|
|
|
44
44
|
)
|
|
45
45
|
|
|
46
46
|
let resolvedQueueOutput = queue->Util_SQS.toResolvedQueueOutput
|
|
47
|
+
let queueResource = queue->Util_SQS.toResource(~tags=tags->Pulumi.Output.fromInput)
|
|
48
|
+
|
|
49
|
+
// Async aggregates and StateChangeSlices land here; same capture so a slice
|
|
50
|
+
// targeting one is routed to it rather than to the plugin's DCB topic.
|
|
51
|
+
CommandTopicRegistry.register(~owner, ~queueUrl=queue.id, ~resource=queueResource, ~isFifo=false)
|
|
47
52
|
|
|
48
53
|
{
|
|
49
54
|
parts: {queue: queue},
|
|
@@ -13,6 +13,7 @@ import * as Util_SQS$ReventlessAws from "../../util/Util_SQS.res.mjs";
|
|
|
13
13
|
import * as Util_Pulumi$ReventlessCore from "@reventlessdev/reventless-core/src/util/Util_Pulumi.res.mjs";
|
|
14
14
|
import * as CommandTopic$ReventlessCore from "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic.res.mjs";
|
|
15
15
|
import * as Util_SQS_FIFO$ReventlessAws from "../../util/Util_SQS_FIFO.res.mjs";
|
|
16
|
+
import * as CommandTopicRegistry$ReventlessAws from "./CommandTopicRegistry.res.mjs";
|
|
16
17
|
import * as Util_DeadLetterQueue$ReventlessAws from "../../util/Util_DeadLetterQueue.res.mjs";
|
|
17
18
|
import * as CommandTopicChannel_SQS$ReventlessAws from "./CommandTopicChannel_SQS.res.mjs";
|
|
18
19
|
import * as CommandTopicChannel_SQS_Runtime$ReventlessAws from "./CommandTopicChannel_SQS_Runtime.res.mjs";
|
|
@@ -31,6 +32,8 @@ function make(name, owner, opts) {
|
|
|
31
32
|
sqsManagedSseEnabled: false
|
|
32
33
|
}, opts$1 !== undefined ? Primitive_option.valFromOption(opts$1) : undefined);
|
|
33
34
|
let resolvedQueueOutput = Util_SQS$ReventlessAws.toResolvedQueueOutput(queue);
|
|
35
|
+
let queueResource = Util_SQS$ReventlessAws.toResource(tags, queue);
|
|
36
|
+
CommandTopicRegistry$ReventlessAws.register(owner, queue.id, queueResource, false);
|
|
34
37
|
return {
|
|
35
38
|
parts: {
|
|
36
39
|
queue: queue
|
|
@@ -33,10 +33,15 @@ let make: ReventlessCore.CommandTopic_Adapter.channelMaker<
|
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
let resolvedQueueOutput = queue->Util_SQS.toResolvedQueueOutput
|
|
36
|
+
let queueResource = queue->Util_SQS_FIFO.toResource(~tags=tags->Pulumi.Output.fromInput)
|
|
37
|
+
|
|
38
|
+
// Same capture as the standard variant, and the reason the flag exists: only
|
|
39
|
+
// the creating module knows this queue needs a MessageGroupId.
|
|
40
|
+
CommandTopicRegistry.register(~owner, ~queueUrl=queue.id, ~resource=queueResource, ~isFifo=true)
|
|
36
41
|
|
|
37
42
|
{
|
|
38
43
|
parts: {queue: queue},
|
|
39
|
-
resources: [
|
|
44
|
+
resources: [queueResource],
|
|
40
45
|
publishJsons: resolvedQueueOutput->Pulumi.Output.apply(resolvedQueue =>
|
|
41
46
|
resolvedQueue->CommandTopicChannel_SQS_Runtime.publishJsons(AWS.SQS_FIFO, ...)
|
|
42
47
|
),
|
|
@@ -13,6 +13,7 @@ import * as Util_SQS$ReventlessAws from "../../util/Util_SQS.res.mjs";
|
|
|
13
13
|
import * as Util_Pulumi$ReventlessCore from "@reventlessdev/reventless-core/src/util/Util_Pulumi.res.mjs";
|
|
14
14
|
import * as CommandTopic$ReventlessCore from "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic.res.mjs";
|
|
15
15
|
import * as Util_SQS_FIFO$ReventlessAws from "../../util/Util_SQS_FIFO.res.mjs";
|
|
16
|
+
import * as CommandTopicRegistry$ReventlessAws from "./CommandTopicRegistry.res.mjs";
|
|
16
17
|
import * as Util_DeadLetterQueue$ReventlessAws from "../../util/Util_DeadLetterQueue.res.mjs";
|
|
17
18
|
import * as CommandTopicChannel_SQS$ReventlessAws from "./CommandTopicChannel_SQS.res.mjs";
|
|
18
19
|
import * as CommandTopicChannel_SQS_Runtime$ReventlessAws from "./CommandTopicChannel_SQS_Runtime.res.mjs";
|
|
@@ -31,11 +32,13 @@ function make(name, owner, opts) {
|
|
|
31
32
|
sqsManagedSseEnabled: false
|
|
32
33
|
}, opts$1 !== undefined ? Primitive_option.valFromOption(opts$1) : undefined);
|
|
33
34
|
let resolvedQueueOutput = Util_SQS$ReventlessAws.toResolvedQueueOutput(queue);
|
|
35
|
+
let queueResource = Util_SQS_FIFO$ReventlessAws.toResource(tags, queue);
|
|
36
|
+
CommandTopicRegistry$ReventlessAws.register(owner, queue.id, queueResource, true);
|
|
34
37
|
return {
|
|
35
38
|
parts: {
|
|
36
39
|
queue: queue
|
|
37
40
|
},
|
|
38
|
-
resources: [
|
|
41
|
+
resources: [queueResource],
|
|
39
42
|
publishJsons: resolvedQueueOutput.apply(resolvedQueue => CommandTopicChannel_SQS_Runtime$ReventlessAws.publishJsons(resolvedQueue, "SQS_FIFO")),
|
|
40
43
|
publishJsonsStream: resolvedQueueOutput.apply(resolvedQueue => {
|
|
41
44
|
let publishJsons = CommandTopicChannel_SQS_Runtime$ReventlessAws.publishJsons(resolvedQueue, "SQS_FIFO");
|
|
@@ -45,10 +45,15 @@ let make: ReventlessCore.CommandTopic_Adapter.channelMaker<
|
|
|
45
45
|
)
|
|
46
46
|
|
|
47
47
|
let resolvedQueueOutput = queue->Util_SQS.toResolvedQueueOutput
|
|
48
|
+
let queueResource = queue->Util_SQS.toResource(~tags=tags->Pulumi.Output.fromInput)
|
|
49
|
+
|
|
50
|
+
// This is the maker Aggregates use, so it is the one an OutboundTranslationSlice
|
|
51
|
+
// naming an Aggregate in `targetName` needs to find.
|
|
52
|
+
CommandTopicRegistry.register(~owner, ~queueUrl=queue.id, ~resource=queueResource, ~isFifo=false)
|
|
48
53
|
|
|
49
54
|
{
|
|
50
55
|
ReventlessCore.CommandTopic_Adapter.parts: {queue: queue},
|
|
51
|
-
resources: [
|
|
56
|
+
resources: [queueResource],
|
|
52
57
|
publishJsons: resolvedQueueOutput->Pulumi.Output.apply(resolvedQueue =>
|
|
53
58
|
resolvedQueue->CommandTopicChannel_SQS_Runtime.publishJsons(AWS.SQS, ...)
|
|
54
59
|
),
|
|
@@ -11,6 +11,7 @@ import * as AWS_Tags$ReventlessAws from "../AWS_Tags.res.mjs";
|
|
|
11
11
|
import * as Util_SQS$ReventlessAws from "../../util/Util_SQS.res.mjs";
|
|
12
12
|
import * as Util_Pulumi$ReventlessCore from "@reventlessdev/reventless-core/src/util/Util_Pulumi.res.mjs";
|
|
13
13
|
import * as CommandTopic$ReventlessCore from "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic.res.mjs";
|
|
14
|
+
import * as CommandTopicRegistry$ReventlessAws from "./CommandTopicRegistry.res.mjs";
|
|
14
15
|
import * as Util_DeadLetterQueue$ReventlessAws from "../../util/Util_DeadLetterQueue.res.mjs";
|
|
15
16
|
import * as CommandTopicChannel_SQS$ReventlessAws from "./CommandTopicChannel_SQS.res.mjs";
|
|
16
17
|
import * as CommandTopicChannel_SQS_Runtime$ReventlessAws from "./CommandTopicChannel_SQS_Runtime.res.mjs";
|
|
@@ -28,11 +29,13 @@ function make(name, owner, opts) {
|
|
|
28
29
|
sqsManagedSseEnabled: false
|
|
29
30
|
}, opts$1 !== undefined ? Primitive_option.valFromOption(opts$1) : undefined);
|
|
30
31
|
let resolvedQueueOutput = Util_SQS$ReventlessAws.toResolvedQueueOutput(queue);
|
|
32
|
+
let queueResource = Util_SQS$ReventlessAws.toResource(tags, queue);
|
|
33
|
+
CommandTopicRegistry$ReventlessAws.register(owner, queue.id, queueResource, false);
|
|
31
34
|
return {
|
|
32
35
|
parts: {
|
|
33
36
|
queue: queue
|
|
34
37
|
},
|
|
35
|
-
resources: [
|
|
38
|
+
resources: [queueResource],
|
|
36
39
|
publishJsons: resolvedQueueOutput.apply(resolvedQueue => CommandTopicChannel_SQS_Runtime$ReventlessAws.publishJsons(resolvedQueue, "SQS")),
|
|
37
40
|
publishJsonsStream: resolvedQueueOutput.apply(resolvedQueue => {
|
|
38
41
|
let publishJsons = CommandTopicChannel_SQS_Runtime$ReventlessAws.publishJsons(resolvedQueue, "SQS");
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Where each component's CommandTopic queue lives, recorded as the queue is
|
|
2
|
+
// created.
|
|
3
|
+
//
|
|
4
|
+
// Runtime code cannot be handed a publisher. A slice Lambda is a compiled
|
|
5
|
+
// EntryPoint configured through `HANDLER_CONFIG`, not a serialized closure —
|
|
6
|
+
// that separation is what fixed the cold-start crashes from closures mixing
|
|
7
|
+
// layer and runtime SDK versions — so a `publishJsons` function cannot cross
|
|
8
|
+
// into it. The same choice has to travel as *data*: which queue, and whether it
|
|
9
|
+
// is FIFO.
|
|
10
|
+
//
|
|
11
|
+
// Captured here rather than recovered later, because recovering it does not
|
|
12
|
+
// work. A component's `resources` array reaches callers inside a
|
|
13
|
+
// `Pulumi.Output.t`, and although every `resource` field is typed
|
|
14
|
+
// `Pulumi.Output.t<string>`, Pulumi flattens nested Outputs at resolution — so
|
|
15
|
+
// within the enclosing apply those fields are already plain strings and calling
|
|
16
|
+
// `.apply` on one throws. At creation the queue is still concrete: `.id` is a
|
|
17
|
+
// flat Output, and the creating module's identity already settles the flavor.
|
|
18
|
+
//
|
|
19
|
+
// Keyed by owner *name* — an Aggregate's `Spec.name` — which is the same key an
|
|
20
|
+
// OutboundTranslationSlice names in `targetName`.
|
|
21
|
+
|
|
22
|
+
type entry = {
|
|
23
|
+
/** The queue URL, for a runtime publisher rebuilt from configuration. */
|
|
24
|
+
queueUrl: Pulumi.Output.t<string>,
|
|
25
|
+
/** The queue as a deploy-time resource, so a caller can add it to a channel
|
|
26
|
+
spec and pick up `connectLambda`'s existing `sqs:SendMessage` grant. */
|
|
27
|
+
resource: ReventlessInfra.Adapter.resource,
|
|
28
|
+
/** FIFO queues need a `MessageGroupId` and standard queues reject one, so this
|
|
29
|
+
cannot be assumed by the caller — it is a property of the queue that only
|
|
30
|
+
the module which created it knows. */
|
|
31
|
+
isFifo: bool,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let byOwner: dict<entry> = Dict.make()
|
|
35
|
+
|
|
36
|
+
let register = (
|
|
37
|
+
~owner: option<ReventlessCore.ResourceAttribution.owner>,
|
|
38
|
+
~queueUrl: Pulumi.Output.t<string>,
|
|
39
|
+
~resource: ReventlessInfra.Adapter.resource,
|
|
40
|
+
~isFifo: bool,
|
|
41
|
+
) =>
|
|
42
|
+
owner->Option.forEach(({name}) =>
|
|
43
|
+
byOwner->Dict.set(name, {queueUrl, resource, isFifo})
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
/** The CommandTopic of the component with this name, if one has been created.
|
|
47
|
+
`None` for a target that is not an Aggregate in this plugin — a DCB
|
|
48
|
+
StateChangeSlice, or a name that matches nothing — where the caller keeps
|
|
49
|
+
the plugin-wide DCB command topic. */
|
|
50
|
+
let get = (name: string) => byOwner->Dict.get(name)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
+
|
|
5
|
+
let byOwner = {};
|
|
6
|
+
|
|
7
|
+
function register(owner, queueUrl, resource, isFifo) {
|
|
8
|
+
Stdlib_Option.forEach(owner, param => {
|
|
9
|
+
byOwner[param.name] = {
|
|
10
|
+
queueUrl: queueUrl,
|
|
11
|
+
resource: resource,
|
|
12
|
+
isFifo: isFifo
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function get(name) {
|
|
18
|
+
return byOwner[name];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
byOwner,
|
|
23
|
+
register,
|
|
24
|
+
get,
|
|
25
|
+
}
|
|
26
|
+
/* No side effect */
|
|
@@ -22,6 +22,7 @@ const dynamicImport = (specifier) => import('/var/task/node_modules/' + specifie
|
|
|
22
22
|
|
|
23
23
|
async function buildAllHandlers() {
|
|
24
24
|
const handlers = {};
|
|
25
|
+
const sweeps = [];
|
|
25
26
|
const entries = Ops.parseHandlerConfig(process.env["HANDLER_CONFIG"] || "");
|
|
26
27
|
|
|
27
28
|
await Promise.all(entries.map(async (entry) => {
|
|
@@ -56,11 +57,28 @@ async function buildAllHandlers() {
|
|
|
56
57
|
? [entry.sourceUrn]
|
|
57
58
|
: [];
|
|
58
59
|
for (const sourceUrn of sourceUrns) {
|
|
59
|
-
StreamOps.addToRegistry(handlers, sourceUrn, registered);
|
|
60
|
+
StreamOps.addToRegistry(handlers, sourceUrn, registered.registered);
|
|
60
61
|
}
|
|
62
|
+
// Every slice can also be swept without an event — see the scheduled branch
|
|
63
|
+
// below. Collected regardless of how many streams it listens on, so a
|
|
64
|
+
// multi-source slice is swept once rather than once per stream.
|
|
65
|
+
sweeps.push(registered);
|
|
61
66
|
}));
|
|
62
67
|
|
|
63
|
-
return handlers;
|
|
68
|
+
return { handlers, sweeps };
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
|
|
71
|
+
const builtPromise = buildAllHandlers();
|
|
72
|
+
const routed = StreamOps.makeRoutedHandler(
|
|
73
|
+
"AutomationSliceRuntime",
|
|
74
|
+
builtPromise.then((b) => b.handlers),
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// The scheduled sweep arrives as the EventBridge rule's constant Input, which
|
|
78
|
+
// has no `records` — so this branch is the one place that must probe an untyped
|
|
79
|
+
// Lambda payload, which is what this shell exists for. Everything it dispatches
|
|
80
|
+
// to is type-checked in AutomationSliceEntryPoint_Ops.
|
|
81
|
+
export const handler = async (event, context) =>
|
|
82
|
+
event?.reventlessSweep
|
|
83
|
+
? Ops.runSweeps((await builtPromise).sweeps)
|
|
84
|
+
: routed(event, context);
|