@reventlessdev/reventless-aws 3.0.0-alpha.232 → 3.0.0-alpha.233
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 +16 -0
- package/package.json +8 -8
- package/src/adapter/Api/AppSyncEventsSigner_Ops.res +137 -0
- package/src/adapter/Api/AppSyncEventsSigner_Ops.res.mjs +121 -0
- package/src/adapter/Api/Platform_AdminScan_Ops.res +136 -0
- package/src/adapter/Api/Platform_AdminScan_Ops.res.mjs +98 -0
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +12 -90
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res.mjs +11 -84
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +86 -0
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res.mjs +79 -0
- package/src/adapter/Api/Platform_UIFragments_Lambda.res +9 -79
- package/src/adapter/Api/Platform_UIFragments_Lambda.res.mjs +7 -143
- package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res +48 -0
- package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res.mjs +63 -0
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +21 -80
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res.mjs +23 -68
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res +70 -0
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res.mjs +68 -0
- package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res +1 -1
- package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res.mjs +1 -1
- package/src/adapter/Postgres/PgMigration_Builder.res +1 -1
- package/src/adapter/Postgres/PgMigration_Builder.res.mjs +1 -1
- package/src/adapter/Runtime/AutomationSliceEntryPoint.mjs +42 -126
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +246 -0
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +145 -0
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +27 -2
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res.mjs +10 -3
- package/src/adapter/Runtime/CounterEntryPoint.mjs +19 -73
- package/src/adapter/Runtime/CounterEntryPoint_Ops.res +145 -0
- package/src/adapter/Runtime/CounterEntryPoint_Ops.res.mjs +129 -0
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +11 -1
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res.mjs +9 -3
- package/src/adapter/Runtime/EventCollectorEntryPoint.mjs +52 -510
- package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +816 -0
- package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res.mjs +651 -0
- package/src/adapter/Runtime/EventMapperEntryPoint.mjs +23 -67
- package/src/adapter/Runtime/EventMapperEntryPoint_Ops.res +126 -0
- package/src/adapter/Runtime/EventMapperEntryPoint_Ops.res.mjs +83 -0
- package/src/adapter/Runtime/ExtensionPointEntryPoint.mjs +16 -63
- package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res +150 -0
- package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res.mjs +111 -0
- package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res +96 -0
- package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res.mjs +70 -0
- package/src/adapter/Runtime/PgMigrationEntryPoint.res +54 -0
- package/src/adapter/Runtime/PgMigrationEntryPoint.res.mjs +37 -0
- package/src/adapter/Runtime/PgQueryResolverEntryPoint.mjs +20 -55
- package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +155 -0
- package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res.mjs +94 -0
- package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res +80 -0
- package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res.mjs +39 -0
- package/src/adapter/Runtime/QueryDbEntryPoint_Ops.res +4 -4
- package/src/adapter/Runtime/ReadModelEntryPoint.mjs +34 -153
- package/src/adapter/Runtime/ReadModelEntryPoint_Ops.res +114 -0
- package/src/adapter/Runtime/ReadModelEntryPoint_Ops.res.mjs +83 -0
- package/src/adapter/Runtime/SideEffectEntryPoint.mjs +23 -64
- package/src/adapter/Runtime/SideEffectEntryPoint_Ops.res +71 -0
- package/src/adapter/Runtime/SideEffectEntryPoint_Ops.res.mjs +57 -0
- package/src/adapter/Runtime/StateViewSliceEntryPoint.mjs +34 -165
- package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +206 -0
- package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res.mjs +105 -0
- package/src/adapter/Runtime/StreamRoutedEntryPoint_Ops.res +156 -0
- package/src/adapter/Runtime/StreamRoutedEntryPoint_Ops.res.mjs +123 -0
- package/src/adapter/Runtime/TaskBucketEntryPoint.mjs +18 -138
- package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +198 -0
- package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res.mjs +155 -0
- package/src/adapter/StateTopic/StateTopic_AppSync.res +12 -170
- package/src/adapter/StateTopic/StateTopic_AppSync.res.mjs +7 -167
- package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res +208 -0
- package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res.mjs +183 -0
- package/src/components/AutomationSlice_Builder.res +2 -0
- package/src/components/AutomationSlice_Builder.res.mjs +1 -1
- package/src/components/OutboundTranslationSlice_Builder.res +1 -0
- package/src/components/OutboundTranslationSlice_Builder.res.mjs +1 -1
- package/tests/AppSyncEventsSigner_OpsTest.res +75 -0
- package/tests/AppSyncEventsSigner_OpsTest.res.mjs +44 -0
- package/tests/AppSyncEventsSigner_ParityFixture.mjs +36 -0
- package/tests/AutomationSliceEntryPoint_OpsTest.res +165 -0
- package/tests/AutomationSliceEntryPoint_OpsTest.res.mjs +280 -0
- package/tests/CounterEntryPoint_OpsTest.res +115 -0
- package/tests/CounterEntryPoint_OpsTest.res.mjs +150 -0
- package/tests/EventCollectorEntryPoint_OpsTest.res +216 -0
- package/tests/EventCollectorEntryPoint_OpsTest.res.mjs +339 -0
- package/tests/EventMapperEntryPoint_OpsTest.res +103 -0
- package/tests/EventMapperEntryPoint_OpsTest.res.mjs +120 -0
- package/tests/ExtensionPointEntryPoint_OpsTest.res +57 -0
- package/tests/ExtensionPointEntryPoint_OpsTest.res.mjs +54 -0
- package/tests/PgMigrationEntryPoint_IntegrationTest.res +22 -31
- package/tests/PgMigrationEntryPoint_IntegrationTest.res.mjs +20 -23
- package/tests/PgQueryResolverEntryPoint_OpsTest.res +38 -0
- package/tests/PgQueryResolverEntryPoint_OpsTest.res.mjs +31 -0
- package/tests/Platform_AdminScan_OpsTest.res +80 -0
- package/tests/Platform_AdminScan_OpsTest.res.mjs +127 -0
- package/tests/ReadModelEntryPoint_OpsTest.res +141 -0
- package/tests/ReadModelEntryPoint_OpsTest.res.mjs +267 -0
- package/tests/SideEffectEntryPoint_OpsTest.res +79 -0
- package/tests/SideEffectEntryPoint_OpsTest.res.mjs +105 -0
- package/tests/StateViewSliceEntryPoint_OpsTest.res +167 -0
- package/tests/StateViewSliceEntryPoint_OpsTest.res.mjs +296 -0
- package/tests/TaskBucketEntryPoint_OpsTest.res +117 -0
- package/tests/TaskBucketEntryPoint_OpsTest.res.mjs +165 -0
- package/tests/integration/StateViewSliceEntryPoint_IntegrationTest.res +42 -13
- package/tests/integration/StateViewSliceEntryPoint_IntegrationTest.res.mjs +29 -6
- package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.mjs +0 -57
- package/src/adapter/Runtime/PgMigrationEntryPoint.mjs +0 -40
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
// EventMapper Lambda entry point (Micro mode).
|
|
2
2
|
// At cold start: reads HANDLER_CONFIG, dynamically imports Target Spec and Mappings,
|
|
3
3
|
// wires EventMapper_Callback.MakeCounterHandler + MakeEventCollectorHandler.
|
|
4
|
+
//
|
|
5
|
+
// Thin untyped shell ("typed core, thin shell" —
|
|
6
|
+
// docs/plans/minimize-lambda-entrypoint-mjs-shell.md): this file owns ONLY the
|
|
7
|
+
// seams that are inherently untyped — the dynamic `import()` of the
|
|
8
|
+
// target-spec/mappings modules named in HANDLER_CONFIG, the shape fix-ups on
|
|
9
|
+
// those runtime-loaded modules (patchSpecId / patchMappingsSourceIds), and the
|
|
10
|
+
// MakeCounterHandler functor application consuming them. HANDLER_CONFIG
|
|
11
|
+
// parsing, the publish/query operations, the MakeEventCollectorHandler
|
|
12
|
+
// application, and the per-source dispatch boundary live type-checked in
|
|
13
|
+
// EventMapperEntryPoint_Ops.res.
|
|
4
14
|
|
|
5
15
|
import { $$String as IdString } from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
log,
|
|
10
|
-
runEffect,
|
|
11
|
-
setRequestId,
|
|
12
|
-
extractMetaField,
|
|
13
|
-
extractSentTimestamp,
|
|
14
|
-
extractRetryCount,
|
|
15
|
-
} from "./HandlerFactoryHelpers.mjs";
|
|
16
|
-
import { MakeCounterHandler, MakeEventCollectorHandler } from "@reventlessdev/reventless-core/src/components/EventMapper/EventMapper_Callback.res.mjs";
|
|
17
|
-
import { publishJsons as sqsPublishJsons } from "@reventlessdev/reventless-aws/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res.mjs";
|
|
18
|
-
import { handleStreamEvent } from "@reventlessdev/reventless-aws/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream_Runtime.res.mjs";
|
|
16
|
+
import { patchSpecId } from "./HandlerFactoryHelpers.mjs";
|
|
17
|
+
import { MakeCounterHandler } from "@reventlessdev/reventless-core/src/components/EventMapper/EventMapper_Callback.res.mjs";
|
|
18
|
+
import * as Ops from "./EventMapperEntryPoint_Ops.res.mjs";
|
|
19
19
|
|
|
20
20
|
const dynamicImport = (specifier) => import('/var/task/node_modules/' + specifier);
|
|
21
21
|
|
|
@@ -33,19 +33,8 @@ function patchMappingsSourceIds(mappingsModule) {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
function
|
|
37
|
-
const
|
|
38
|
-
records.forEach(record => {
|
|
39
|
-
const arn = record.eventSourceARN;
|
|
40
|
-
const existing = dict[arn] || [];
|
|
41
|
-
dict[arn] = existing.concat([record]);
|
|
42
|
-
});
|
|
43
|
-
return dict;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async function buildHandler() {
|
|
47
|
-
const configStr = process.env["HANDLER_CONFIG"] || "{}";
|
|
48
|
-
const config = JSON.parse(configStr);
|
|
36
|
+
async function build() {
|
|
37
|
+
const config = Ops.parseHandlerConfig(process.env["HANDLER_CONFIG"] || "{}");
|
|
49
38
|
|
|
50
39
|
const targetSpecModule = await dynamicImport(config.targetSpecModule);
|
|
51
40
|
const mappingsModule = await dynamicImport(config.mappingsModule);
|
|
@@ -53,47 +42,14 @@ async function buildHandler() {
|
|
|
53
42
|
const patchedTarget = patchSpecId(targetSpecModule);
|
|
54
43
|
const patchedMappings = patchMappingsSourceIds(mappingsModule);
|
|
55
44
|
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
query: async () => { log.error("queryEngine not available in bundled mode", { comp: "EventMapperEntryPoint" }); return []; },
|
|
59
|
-
get: async () => { log.error("queryEngine not available in bundled mode", { comp: "EventMapperEntryPoint" }); return undefined; },
|
|
60
|
-
};
|
|
45
|
+
const counterOps = Ops.makeCounterOps(config);
|
|
46
|
+
const counterHandler = MakeCounterHandler(patchedTarget)(patchedMappings)(counterOps);
|
|
61
47
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
addToCounterTarget: noopAsync,
|
|
68
|
-
commonEventsHandler: counterHandler.commonEventsHandler,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
streamHandler: (event, context) =>
|
|
73
|
-
handleStreamEvent(eventCollectorHandler.handleJsonEvents, event, context),
|
|
74
|
-
// The mapper is named after the target it maps into.
|
|
75
|
-
comp: `EventMapper(${patchedTarget.name})`,
|
|
76
|
-
};
|
|
48
|
+
// The mapper is named after the target it maps into.
|
|
49
|
+
return [
|
|
50
|
+
Ops.makeStreamHandler(counterOps, counterHandler.commonEventsHandler),
|
|
51
|
+
`EventMapper(${patchedTarget.name})`,
|
|
52
|
+
];
|
|
77
53
|
}
|
|
78
54
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
export async function handler(event, context) {
|
|
82
|
-
setRequestId(context?.awsRequestId);
|
|
83
|
-
const { streamHandler, comp } = await initPromise;
|
|
84
|
-
const records = event.Records || [];
|
|
85
|
-
const grouped = groupBySource(records);
|
|
86
|
-
|
|
87
|
-
await Promise.all(Object.entries(grouped).map(async ([arn, subRecords]) => {
|
|
88
|
-
log.debug("processing " + arn, { comp: "EventMapperRuntime" });
|
|
89
|
-
await runEffect(streamHandler({ Records: subRecords }, context), {
|
|
90
|
-
correlationId: extractMetaField(subRecords, "correlationId"),
|
|
91
|
-
causationId: extractMetaField(subRecords, "causationId"),
|
|
92
|
-
comp,
|
|
93
|
-
timestamp: extractSentTimestamp(subRecords),
|
|
94
|
-
retryCount: extractRetryCount(subRecords),
|
|
95
|
-
});
|
|
96
|
-
}));
|
|
97
|
-
|
|
98
|
-
return "";
|
|
99
|
-
}
|
|
55
|
+
export const handler = Ops.makeHandler(build());
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// Typed cold-start core for the EventMapper Lambda entry point (Micro mode).
|
|
2
|
+
//
|
|
3
|
+
// The "typed core, thin shell" split (docs/plans/minimize-lambda-entrypoint-mjs-shell.md):
|
|
4
|
+
// EventMapperEntryPoint.mjs keeps only the untyped seam — the dynamic
|
|
5
|
+
// `import()` of the target-spec/mappings modules named in HANDLER_CONFIG, the
|
|
6
|
+
// `patchSpecId` / mapping-Source-Id fix-ups, and the
|
|
7
|
+
// EventMapper_Callback.MakeCounterHandler functor application consuming them.
|
|
8
|
+
// HANDLER_CONFIG parsing, the publish/query operations, the
|
|
9
|
+
// MakeEventCollectorHandler application (a functor over an inline module
|
|
10
|
+
// capturing runtime values), and the per-source dispatch boundary live here,
|
|
11
|
+
// fully type-checked.
|
|
12
|
+
//
|
|
13
|
+
// The former shell's queryEngine stub carried wrong field names
|
|
14
|
+
// (`query`/`get` for QueryEngine.operations' `scan`/`query`) — a mapping
|
|
15
|
+
// calling `scan` crashed with "not a function" instead of the intended
|
|
16
|
+
// logged-error fallback. The typed record fixes the shape; both operations
|
|
17
|
+
// still log an error and return [] (not available in the bundled handler).
|
|
18
|
+
|
|
19
|
+
// ── HANDLER_CONFIG ──────────────────────────────────────────────────────────
|
|
20
|
+
// Written by AggregateRuntime_Builder_Micro / _Micro_Async.
|
|
21
|
+
|
|
22
|
+
type handlerConfig = {
|
|
23
|
+
targetSpecModule?: string,
|
|
24
|
+
mappingsModule?: string,
|
|
25
|
+
queueUrl?: string,
|
|
26
|
+
}
|
|
27
|
+
@val @scope("JSON") external jsonParse: string => handlerConfig = "parse"
|
|
28
|
+
// A real binding (not a bare external) so the shell can import it.
|
|
29
|
+
let parseHandlerConfig = (raw: string): handlerConfig => jsonParse(raw)
|
|
30
|
+
|
|
31
|
+
// ── Counter-handler operations (third argument of MakeCounterHandler) ───────
|
|
32
|
+
|
|
33
|
+
type counterOps = {
|
|
34
|
+
publishJsons: ReventlessCore.CommandTopic.publishJsons,
|
|
35
|
+
queryEngine: Reventless.QueryEngine.operations,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let makeCounterOps = (config: handlerConfig): counterOps => {
|
|
39
|
+
let queueUrl = config.queueUrl->Option.getOr("")
|
|
40
|
+
let queue: Util_SQS_Runtime.resolvedQueue = {id: queueUrl, name: queueUrl, arn: ""}
|
|
41
|
+
{
|
|
42
|
+
publishJsons: queue->CommandTopicChannel_SQS_Runtime.publishJsons(AWS.SQS_FIFO),
|
|
43
|
+
queryEngine: {
|
|
44
|
+
scan: async (~readModelName as _, ~filterConfigs as _, ~limit as _) => {
|
|
45
|
+
StreamRoutedEntryPoint_Ops.logError(
|
|
46
|
+
"queryEngine not available in bundled mode",
|
|
47
|
+
{comp: "EventMapperEntryPoint"},
|
|
48
|
+
)
|
|
49
|
+
[]
|
|
50
|
+
},
|
|
51
|
+
query: async (
|
|
52
|
+
~readModelName as _,
|
|
53
|
+
~key as _=?,
|
|
54
|
+
~id as _,
|
|
55
|
+
~subIdConfig as _=?,
|
|
56
|
+
~filterConfigs as _=?,
|
|
57
|
+
~ascending as _=?,
|
|
58
|
+
~limit as _=?,
|
|
59
|
+
) => {
|
|
60
|
+
StreamRoutedEntryPoint_Ops.logError(
|
|
61
|
+
"queryEngine not available in bundled mode",
|
|
62
|
+
{comp: "EventMapperEntryPoint"},
|
|
63
|
+
)
|
|
64
|
+
[]
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ── Stream handler ──────────────────────────────────────────────────────────
|
|
71
|
+
// `commonEventsHandler` comes off the shell's MakeCounterHandler application
|
|
72
|
+
// (it consumes the runtime-loaded target/mappings modules); everything it
|
|
73
|
+
// feeds — counter no-ops, publishing, the stream wrap — is typed.
|
|
74
|
+
|
|
75
|
+
type commonEventsHandler = array<JSON.t> => promise<(
|
|
76
|
+
promise<array<ReventlessCore.Message.commandJson>>,
|
|
77
|
+
array<ReventlessCore.Counter.action>,
|
|
78
|
+
)>
|
|
79
|
+
|
|
80
|
+
let makeStreamHandler = (
|
|
81
|
+
ops: counterOps,
|
|
82
|
+
commonEventsHandler: commonEventsHandler,
|
|
83
|
+
): StreamRoutedEntryPoint_Ops.streamHandler => {
|
|
84
|
+
module Handler = ReventlessCore.EventMapper_Callback.MakeEventCollectorHandler({
|
|
85
|
+
let publishJsons = ops.publishJsons
|
|
86
|
+
let count: ReventlessCore.Counter.count = async _ => ()
|
|
87
|
+
let addToCounterTarget: ReventlessCore.Counter.addToCounterTarget = async _ => ()
|
|
88
|
+
let commonEventsHandler = commonEventsHandler
|
|
89
|
+
})
|
|
90
|
+
StreamRoutedEntryPoint_Ops.toStreamHandler(Handler.handleJsonEvents)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ── Dispatch boundary ───────────────────────────────────────────────────────
|
|
94
|
+
// Unlike the registry-routed entry points (one Lambda, many components), the
|
|
95
|
+
// mapper Lambda serves a single target: every source group runs the same
|
|
96
|
+
// handler, attributed `EventMapper(<Target>)`.
|
|
97
|
+
|
|
98
|
+
let makeHandler = (
|
|
99
|
+
buildPromise: promise<(StreamRoutedEntryPoint_Ops.streamHandler, string)>,
|
|
100
|
+
) =>
|
|
101
|
+
async (event: PulumiAws.Lambda.CallbackFunction.event, context: PulumiAws.Lambda.context) => {
|
|
102
|
+
StreamRoutedEntryPoint_Ops.setRequestId(context.awsRequestId)
|
|
103
|
+
let (streamHandler, comp) = await buildPromise
|
|
104
|
+
let _ =
|
|
105
|
+
await StreamRoutedEntryPoint_Ops.groupBySource(event.records)
|
|
106
|
+
->Dict.toArray
|
|
107
|
+
->Array.map(async ((arn, subRecords)) => {
|
|
108
|
+
StreamRoutedEntryPoint_Ops.logDebug("processing " ++ arn, {comp: "EventMapperRuntime"})
|
|
109
|
+
let subEvent: PulumiAws.Lambda.CallbackFunction.event = {records: subRecords}
|
|
110
|
+
await StreamRoutedEntryPoint_Ops.runEffect(
|
|
111
|
+
streamHandler(subEvent, context),
|
|
112
|
+
{
|
|
113
|
+
correlationId: ?StreamRoutedEntryPoint_Ops.extractMetaField(
|
|
114
|
+
subRecords,
|
|
115
|
+
"correlationId",
|
|
116
|
+
),
|
|
117
|
+
causationId: ?StreamRoutedEntryPoint_Ops.extractMetaField(subRecords, "causationId"),
|
|
118
|
+
comp,
|
|
119
|
+
timestamp: ?StreamRoutedEntryPoint_Ops.extractSentTimestamp(subRecords),
|
|
120
|
+
retryCount: StreamRoutedEntryPoint_Ops.extractRetryCount(subRecords),
|
|
121
|
+
},
|
|
122
|
+
)
|
|
123
|
+
})
|
|
124
|
+
->Promise.all
|
|
125
|
+
""
|
|
126
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
+
import * as EventMapper_Callback$ReventlessCore from "@reventlessdev/reventless-core/src/components/EventMapper/EventMapper_Callback.res.mjs";
|
|
5
|
+
import * as StreamRoutedEntryPoint_Ops$ReventlessAws from "./StreamRoutedEntryPoint_Ops.res.mjs";
|
|
6
|
+
import * as CommandTopicChannel_SQS_Runtime$ReventlessAws from "../CommandTopic/CommandTopicChannel_SQS_Runtime.res.mjs";
|
|
7
|
+
|
|
8
|
+
function parseHandlerConfig(raw) {
|
|
9
|
+
return JSON.parse(raw);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function makeCounterOps(config) {
|
|
13
|
+
let queueUrl = Stdlib_Option.getOr(config.queueUrl, "");
|
|
14
|
+
let queue = {
|
|
15
|
+
id: queueUrl,
|
|
16
|
+
name: queueUrl,
|
|
17
|
+
arn: ""
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
publishJsons: CommandTopicChannel_SQS_Runtime$ReventlessAws.publishJsons(queue, "SQS_FIFO"),
|
|
21
|
+
queryEngine: {
|
|
22
|
+
scan: async (param, param$1, param$2) => {
|
|
23
|
+
StreamRoutedEntryPoint_Ops$ReventlessAws.logError("queryEngine not available in bundled mode", {
|
|
24
|
+
comp: "EventMapperEntryPoint"
|
|
25
|
+
});
|
|
26
|
+
return [];
|
|
27
|
+
},
|
|
28
|
+
query: async (param, param$1, param$2, param$3, param$4, param$5, param$6) => {
|
|
29
|
+
StreamRoutedEntryPoint_Ops$ReventlessAws.logError("queryEngine not available in bundled mode", {
|
|
30
|
+
comp: "EventMapperEntryPoint"
|
|
31
|
+
});
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function makeStreamHandler(ops, commonEventsHandler) {
|
|
39
|
+
let publishJsons = ops.publishJsons;
|
|
40
|
+
let count = async param => {};
|
|
41
|
+
let addToCounterTarget = async param => {};
|
|
42
|
+
let Handler = EventMapper_Callback$ReventlessCore.MakeEventCollectorHandler({
|
|
43
|
+
publishJsons: publishJsons,
|
|
44
|
+
count: count,
|
|
45
|
+
addToCounterTarget: addToCounterTarget,
|
|
46
|
+
commonEventsHandler: commonEventsHandler
|
|
47
|
+
});
|
|
48
|
+
return StreamRoutedEntryPoint_Ops$ReventlessAws.toStreamHandler(Handler.handleJsonEvents);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function makeHandler(buildPromise) {
|
|
52
|
+
return async (event, context) => {
|
|
53
|
+
StreamRoutedEntryPoint_Ops$ReventlessAws.setRequestId(context.awsRequestId);
|
|
54
|
+
let match = await buildPromise;
|
|
55
|
+
let comp = match[1];
|
|
56
|
+
let streamHandler = match[0];
|
|
57
|
+
await Promise.all(Object.entries(StreamRoutedEntryPoint_Ops$ReventlessAws.groupBySource(event.Records)).map(async param => {
|
|
58
|
+
let subRecords = param[1];
|
|
59
|
+
StreamRoutedEntryPoint_Ops$ReventlessAws.logDebug("processing " + param[0], {
|
|
60
|
+
comp: "EventMapperRuntime"
|
|
61
|
+
});
|
|
62
|
+
let subEvent = {
|
|
63
|
+
Records: subRecords
|
|
64
|
+
};
|
|
65
|
+
return await StreamRoutedEntryPoint_Ops$ReventlessAws.runEffect(streamHandler(subEvent, context), {
|
|
66
|
+
correlationId: StreamRoutedEntryPoint_Ops$ReventlessAws.extractMetaField(subRecords, "correlationId"),
|
|
67
|
+
causationId: StreamRoutedEntryPoint_Ops$ReventlessAws.extractMetaField(subRecords, "causationId"),
|
|
68
|
+
comp: comp,
|
|
69
|
+
timestamp: StreamRoutedEntryPoint_Ops$ReventlessAws.extractSentTimestamp(subRecords),
|
|
70
|
+
retryCount: StreamRoutedEntryPoint_Ops$ReventlessAws.extractRetryCount(subRecords)
|
|
71
|
+
});
|
|
72
|
+
}));
|
|
73
|
+
return "";
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export {
|
|
78
|
+
parseHandlerConfig,
|
|
79
|
+
makeCounterOps,
|
|
80
|
+
makeStreamHandler,
|
|
81
|
+
makeHandler,
|
|
82
|
+
}
|
|
83
|
+
/* EventMapper_Callback-ReventlessCore Not a pure module */
|
|
@@ -2,84 +2,37 @@
|
|
|
2
2
|
// At cold start: reads HANDLER_CONFIG, dynamically imports Spec/Mappings,
|
|
3
3
|
// wires ExtensionPoint_Callback.Make + CommandTopic_Callback.Make,
|
|
4
4
|
// routes SQS events through handleQueueEvent.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "./HandlerFactoryHelpers.mjs";
|
|
5
|
+
//
|
|
6
|
+
// Thin untyped shell ("typed core, thin shell" —
|
|
7
|
+
// docs/plans/minimize-lambda-entrypoint-mjs-shell.md): this file owns ONLY the
|
|
8
|
+
// seams that are inherently untyped — the dynamic `import()` of the
|
|
9
|
+
// spec/mappings modules named in HANDLER_CONFIG, the `patchSpecId` fix-up, and
|
|
10
|
+
// the two functor applications consuming them. The callback config,
|
|
11
|
+
// HANDLER_CONFIG parsing, and the SQS dispatch boundary live type-checked in
|
|
12
|
+
// ExtensionPointEntryPoint_Ops.res.
|
|
13
|
+
|
|
14
|
+
import { patchSpecId } from "./HandlerFactoryHelpers.mjs";
|
|
16
15
|
import { Make as extensionPointCallbackMake } from "@reventlessdev/reventless-core/src/components/ExtensionPoint/ExtensionPoint_Callback.res.mjs";
|
|
17
16
|
import { Make as commandTopicCallbackMake } from "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic_Callback.res.mjs";
|
|
18
|
-
import
|
|
17
|
+
import * as Ops from "./ExtensionPointEntryPoint_Ops.res.mjs";
|
|
19
18
|
|
|
20
19
|
const dynamicImport = (specifier) => import('/var/task/node_modules/' + specifier);
|
|
21
20
|
|
|
22
|
-
async function
|
|
23
|
-
const
|
|
24
|
-
const config = JSON.parse(configStr);
|
|
21
|
+
async function build() {
|
|
22
|
+
const config = Ops.parseHandlerConfig(process.env["HANDLER_CONFIG"] || "{}");
|
|
25
23
|
|
|
26
24
|
const specModule = await dynamicImport(config.specModule);
|
|
27
25
|
const mappingsModule = await dynamicImport(config.mappingsModule);
|
|
28
26
|
|
|
29
27
|
const patchedSpec = patchSpecId(specModule);
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
// builder writes HANDLER_CONFIG.publishToAggregates as { aggregateName: envVarName }
|
|
33
|
-
// (see ExtensionPointRuntime_Builder_PerExtensionPoint.res), so iterate accordingly.
|
|
34
|
-
const publishToAggregates = {};
|
|
35
|
-
for (const [aggName, envVarName] of Object.entries(config.publishToAggregates || {})) {
|
|
36
|
-
const queueUrl = process.env[envVarName] || "";
|
|
37
|
-
publishToAggregates[aggName] = sqsPublishJsons(makeQueueRef(queueUrl), "SQS_FIFO");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const callbackConfig = {
|
|
41
|
-
publishToAggregates,
|
|
42
|
-
commandTopicResources: [],
|
|
43
|
-
scheduler: {
|
|
44
|
-
create: async () => { throw new Error("Scheduler not available in bundled ExtensionPoint handler"); },
|
|
45
|
-
delete: async () => { throw new Error("Scheduler not available in bundled ExtensionPoint handler"); },
|
|
46
|
-
},
|
|
47
|
-
queryEngine: {
|
|
48
|
-
scan: async () => { throw new Error("QueryEngine not available in bundled ExtensionPoint handler"); },
|
|
49
|
-
query: async () => { throw new Error("QueryEngine not available in bundled ExtensionPoint handler"); },
|
|
50
|
-
},
|
|
51
|
-
resourceNaming: { name: (n) => n, resolve: (n) => n },
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const callback = extensionPointCallbackMake(callbackConfig)(patchedSpec)(mappingsModule);
|
|
29
|
+
const callback = extensionPointCallbackMake(Ops.makeCallbackSpec(config))(patchedSpec)(mappingsModule);
|
|
55
30
|
const commandTopicCallback = commandTopicCallbackMake(patchedSpec)({
|
|
56
31
|
Spec: patchedSpec,
|
|
57
32
|
commandsHandler: callback.handleIncomingCommands,
|
|
58
33
|
});
|
|
59
34
|
|
|
60
|
-
|
|
61
|
-
// Pair the handler with the extension point it serves so the invocation's log
|
|
62
|
-
// lines name the component, not just this Lambda.
|
|
63
|
-
return {
|
|
64
|
-
sqsHandler: handleQueueEvent(resolvedQueue, commandTopicCallback.handleJsonCommands),
|
|
65
|
-
comp: `ExtensionPoint(${patchedSpec.name})`,
|
|
66
|
-
};
|
|
35
|
+
return Ops.makeBuilt(config, patchedSpec.name, commandTopicCallback.handleJsonCommands);
|
|
67
36
|
}
|
|
68
37
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
export async function handler(event, context) {
|
|
72
|
-
setRequestId(context?.awsRequestId);
|
|
73
|
-
const { sqsHandler, comp } = await initPromise;
|
|
74
|
-
const records = event.Records || [];
|
|
75
|
-
|
|
76
|
-
log.debug("processing " + records.length.toString() + " record(s)", { comp: "ExtensionPointRuntime" });
|
|
77
|
-
await runEffect(sqsHandler(event, context), {
|
|
78
|
-
correlationId: extractMetaField(records, "correlationId"),
|
|
79
|
-
causationId: extractMetaField(records, "causationId"),
|
|
80
|
-
comp,
|
|
81
|
-
timestamp: extractSentTimestamp(records),
|
|
82
|
-
retryCount: extractRetryCount(records),
|
|
83
|
-
});
|
|
84
|
-
return "";
|
|
85
|
-
}
|
|
38
|
+
export const handler = Ops.makeHandler(build());
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Typed cold-start core for the (per-extension-point) ExtensionPoint Lambda
|
|
2
|
+
// entry point.
|
|
3
|
+
//
|
|
4
|
+
// The "typed core, thin shell" split (docs/plans/minimize-lambda-entrypoint-mjs-shell.md):
|
|
5
|
+
// ExtensionPointEntryPoint.mjs keeps only the untyped seam — the dynamic
|
|
6
|
+
// `import()` of the spec/mappings modules named in HANDLER_CONFIG, the
|
|
7
|
+
// `patchSpecId` fix-up, and the ExtensionPoint_Callback.Make /
|
|
8
|
+
// CommandTopic_Callback.Make functor applications consuming them. The callback
|
|
9
|
+
// config (publish dict, scheduler/query stubs, resource naming), HANDLER_CONFIG
|
|
10
|
+
// parsing, and the SQS dispatch boundary live here, fully type-checked.
|
|
11
|
+
//
|
|
12
|
+
// The former shell's stub records carried wrong field names (`create`/`delete`
|
|
13
|
+
// for Scheduler.operations' `createSchedule`/`deleteSchedule`, `name`/`resolve`
|
|
14
|
+
// for ResourceNaming.operations' `validateName`/`urnName`) — a mapping touching
|
|
15
|
+
// them crashed with "not a function" instead of the intended error. The typed
|
|
16
|
+
// records fix the shapes; scheduler/queryEngine still throw by design (not
|
|
17
|
+
// available in the bundled handler).
|
|
18
|
+
|
|
19
|
+
@val @scope("process") external processEnv: dict<string> = "env"
|
|
20
|
+
|
|
21
|
+
// ── Shim bindings (HandlerFactoryHelpers.mjs), typed for SQS records ────────
|
|
22
|
+
@module("./HandlerFactoryHelpers.mjs")
|
|
23
|
+
external setRequestId: string => unit = "setRequestId"
|
|
24
|
+
@module("./HandlerFactoryHelpers.mjs")
|
|
25
|
+
external runEffect: (
|
|
26
|
+
Effect.t<'a, 'e, 'r>,
|
|
27
|
+
StreamRoutedEntryPoint_Ops.dispatchOpts,
|
|
28
|
+
) => promise<unit> = "runEffect"
|
|
29
|
+
@module("./HandlerFactoryHelpers.mjs")
|
|
30
|
+
external extractMetaField: (array<PulumiAws.SQS.Queue.record>, string) => option<string> =
|
|
31
|
+
"extractMetaField"
|
|
32
|
+
@module("./HandlerFactoryHelpers.mjs")
|
|
33
|
+
external extractSentTimestamp: array<PulumiAws.SQS.Queue.record> => option<float> =
|
|
34
|
+
"extractSentTimestamp"
|
|
35
|
+
@module("./HandlerFactoryHelpers.mjs")
|
|
36
|
+
external extractRetryCount: array<PulumiAws.SQS.Queue.record> => int = "extractRetryCount"
|
|
37
|
+
@module("./HandlerFactoryHelpers.mjs") @scope("log")
|
|
38
|
+
external logDebug: (string, StreamRoutedEntryPoint_Ops.dispatchOpts) => unit = "debug"
|
|
39
|
+
|
|
40
|
+
// ── HANDLER_CONFIG ──────────────────────────────────────────────────────────
|
|
41
|
+
// Written by ExtensionPointRuntime_Builder_PerExtensionPoint; all fields
|
|
42
|
+
// optional so a partial config degrades like the former shell's `|| ""` reads.
|
|
43
|
+
|
|
44
|
+
type handlerConfig = {
|
|
45
|
+
specModule?: string,
|
|
46
|
+
mappingsModule?: string,
|
|
47
|
+
queueUrl?: string,
|
|
48
|
+
// aggregateName → env-var name holding the aggregate's cmd-topic SQS URL.
|
|
49
|
+
publishToAggregates?: dict<string>,
|
|
50
|
+
}
|
|
51
|
+
@val @scope("JSON") external jsonParse: string => handlerConfig = "parse"
|
|
52
|
+
// A real binding (not a bare external) so the shell can import it.
|
|
53
|
+
let parseHandlerConfig = (raw: string): handlerConfig => jsonParse(raw)
|
|
54
|
+
|
|
55
|
+
// ── Callback config (first argument of ExtensionPoint_Callback.Make) ────────
|
|
56
|
+
// The record's field names/types mirror ExtensionPoint_Callback's `Spec` module
|
|
57
|
+
// type — the compiled functor consumes it as a plain object.
|
|
58
|
+
|
|
59
|
+
type callbackSpec = {
|
|
60
|
+
publishToAggregates: dict<ReventlessCore.CommandTopic.publishJsons>,
|
|
61
|
+
commandTopicResources: array<ReventlessInfra.Adapter.resolvedResource>,
|
|
62
|
+
scheduler: ReventlessCore.Scheduler.operations,
|
|
63
|
+
queryEngine: Reventless.QueryEngine.operations,
|
|
64
|
+
resourceNaming: ReventlessInfra.ResourceNaming.operations,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let makeCallbackSpec = (config: handlerConfig): callbackSpec => {
|
|
68
|
+
publishToAggregates: config.publishToAggregates
|
|
69
|
+
->Option.getOr(Dict.make())
|
|
70
|
+
->Dict.toArray
|
|
71
|
+
->Array.map(((aggName, envVarName)) => {
|
|
72
|
+
let queueUrl = processEnv->Dict.get(envVarName)->Option.getOr("")
|
|
73
|
+
let queue: Util_SQS_Runtime.resolvedQueue = {id: queueUrl, name: queueUrl, arn: ""}
|
|
74
|
+
(aggName, queue->CommandTopicChannel_SQS_Runtime.publishJsons(AWS.SQS_FIFO))
|
|
75
|
+
})
|
|
76
|
+
->Dict.fromArray,
|
|
77
|
+
commandTopicResources: [],
|
|
78
|
+
scheduler: {
|
|
79
|
+
createSchedule: (_, _) =>
|
|
80
|
+
JsError.throwWithMessage("Scheduler not available in bundled ExtensionPoint handler"),
|
|
81
|
+
deleteSchedule: (_, _) =>
|
|
82
|
+
JsError.throwWithMessage("Scheduler not available in bundled ExtensionPoint handler"),
|
|
83
|
+
},
|
|
84
|
+
queryEngine: {
|
|
85
|
+
scan: (~readModelName as _, ~filterConfigs as _, ~limit as _) =>
|
|
86
|
+
JsError.throwWithMessage("QueryEngine not available in bundled ExtensionPoint handler"),
|
|
87
|
+
query: (
|
|
88
|
+
~readModelName as _,
|
|
89
|
+
~key as _=?,
|
|
90
|
+
~id as _,
|
|
91
|
+
~subIdConfig as _=?,
|
|
92
|
+
~filterConfigs as _=?,
|
|
93
|
+
~ascending as _=?,
|
|
94
|
+
~limit as _=?,
|
|
95
|
+
) => JsError.throwWithMessage("QueryEngine not available in bundled ExtensionPoint handler"),
|
|
96
|
+
},
|
|
97
|
+
resourceNaming: {
|
|
98
|
+
validateName: n => n,
|
|
99
|
+
urnName: n => n,
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ── SQS dispatch boundary ───────────────────────────────────────────────────
|
|
104
|
+
// The shell resolves the spec module, applies the functors, and hands the
|
|
105
|
+
// typed jsonCommandsHandler back here; `comp` pairs the invocation's log lines
|
|
106
|
+
// with the extension point the Lambda serves, not just the Lambda itself.
|
|
107
|
+
|
|
108
|
+
type built = {
|
|
109
|
+
comp: string,
|
|
110
|
+
sqsHandler: (
|
|
111
|
+
PulumiAws.SQS.Queue.event,
|
|
112
|
+
PulumiAws.Lambda.context,
|
|
113
|
+
) => Effect.t<unit, string, unit>,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let makeBuilt = (
|
|
117
|
+
config: handlerConfig,
|
|
118
|
+
specName: string,
|
|
119
|
+
handleJsonCommands: ReventlessCore.CommandTopic.jsonCommandsHandler,
|
|
120
|
+
): built => {
|
|
121
|
+
let queueUrl = config.queueUrl->Option.getOr("")
|
|
122
|
+
let queue: Util_SQS_Runtime.resolvedQueue = {id: queueUrl, name: queueUrl, arn: ""}
|
|
123
|
+
{
|
|
124
|
+
comp: `ExtensionPoint(${specName})`,
|
|
125
|
+
sqsHandler: CommandTopicChannel_SQS_Runtime.handleQueueEvent(queue, handleJsonCommands),
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let makeHandler = (buildPromise: promise<built>) =>
|
|
130
|
+
async (event: PulumiAws.SQS.Queue.event, context: PulumiAws.Lambda.context) => {
|
|
131
|
+
setRequestId(context.awsRequestId)
|
|
132
|
+
let {comp, sqsHandler} = await buildPromise
|
|
133
|
+
let records = event.records
|
|
134
|
+
|
|
135
|
+
logDebug(
|
|
136
|
+
`processing ${records->Array.length->Int.toString} record(s)`,
|
|
137
|
+
{comp: "ExtensionPointRuntime"},
|
|
138
|
+
)
|
|
139
|
+
await runEffect(
|
|
140
|
+
sqsHandler(event, context),
|
|
141
|
+
{
|
|
142
|
+
correlationId: ?extractMetaField(records, "correlationId"),
|
|
143
|
+
causationId: ?extractMetaField(records, "causationId"),
|
|
144
|
+
comp,
|
|
145
|
+
timestamp: ?extractSentTimestamp(records),
|
|
146
|
+
retryCount: extractRetryCount(records),
|
|
147
|
+
},
|
|
148
|
+
)
|
|
149
|
+
""
|
|
150
|
+
}
|