@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
|
@@ -2,90 +2,36 @@
|
|
|
2
2
|
// At cold start: reads HANDLER_CONFIG, dynamically imports Target Spec and Mappings,
|
|
3
3
|
// wires Counter_Callback.Make + EventMapper_Callback.MakeCounterHandler.
|
|
4
4
|
// Routes DynamoDB Stream events from references and counts tables.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
+
// target-spec/mappings modules named in HANDLER_CONFIG, the `patchSpecId`
|
|
10
|
+
// fix-up, and the MakeCounterHandler functor application consuming them.
|
|
11
|
+
// HANDLER_CONFIG parsing, the Counter_Callback.Make application, and the
|
|
12
|
+
// references/counts stream routing live type-checked in
|
|
13
|
+
// CounterEntryPoint_Ops.res.
|
|
14
|
+
|
|
15
|
+
import { patchSpecId } from "./HandlerFactoryHelpers.mjs";
|
|
10
16
|
import { MakeCounterHandler } from "@reventlessdev/reventless-core/src/components/EventMapper/EventMapper_Callback.res.mjs";
|
|
11
|
-
import
|
|
12
|
-
import { publishJsons as sqsPublishJsons } from "@reventlessdev/reventless-aws/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res.mjs";
|
|
17
|
+
import * as Ops from "./CounterEntryPoint_Ops.res.mjs";
|
|
13
18
|
|
|
14
19
|
const dynamicImport = (specifier) => import('/var/task/node_modules/' + specifier);
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
id: s.m(suryString),
|
|
19
|
-
inc: s.m(suryInt),
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
async function buildHandler() {
|
|
23
|
-
const configStr = process.env["HANDLER_CONFIG"] || "{}";
|
|
24
|
-
const config = JSON.parse(configStr);
|
|
21
|
+
async function build() {
|
|
22
|
+
const config = Ops.parseHandlerConfig(process.env["HANDLER_CONFIG"] || "{}");
|
|
25
23
|
|
|
26
24
|
const targetSpecModule = await dynamicImport(config.targetSpecModule);
|
|
27
25
|
const mappingsModule = await dynamicImport(config.mappingsModule);
|
|
28
26
|
|
|
29
27
|
const patchedTarget = patchSpecId(targetSpecModule);
|
|
30
|
-
const
|
|
31
|
-
const countsDbCount = qdbCount(countsTable);
|
|
32
|
-
|
|
33
|
-
const pubJsons = sqsPublishJsons(makeQueueRef(config.publishQueueUrl), "SQS_FIFO");
|
|
34
|
-
const queryEngine = { query: async () => [], queryAll: async () => [] };
|
|
28
|
+
const counterHandler = MakeCounterHandler(patchedTarget)(mappingsModule)(Ops.makeCounterOps(config));
|
|
35
29
|
|
|
36
|
-
|
|
37
|
-
const callback = counterCallbackMake({
|
|
38
|
-
name: "BundledCounter",
|
|
39
|
-
countsDbCount,
|
|
40
|
-
jsonEventsHandler: counterHandler.handleCounterEvents,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
return [config.referencesStreamArn, config.countsStreamArn, callback];
|
|
30
|
+
return Ops.makeHandler(config, counterHandler.handleCounterEvents);
|
|
44
31
|
}
|
|
45
32
|
|
|
46
|
-
const initPromise =
|
|
47
|
-
|
|
48
|
-
export async function handler(event, _context) {
|
|
49
|
-
const [referencesStreamArn, countsStreamArn, callback] = await initPromise;
|
|
50
|
-
const records = event.Records || [];
|
|
51
|
-
|
|
52
|
-
const dynamoDbRecords = records.filter(r =>
|
|
53
|
-
r.eventSource === "aws:dynamodb" &&
|
|
54
|
-
(r.eventSourceARN === referencesStreamArn || r.eventSourceARN === countsStreamArn)
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
const referenceRecords = dynamoDbRecords.filter(r => r.eventSourceARN === referencesStreamArn);
|
|
58
|
-
const countRecords = dynamoDbRecords.filter(r => r.eventSourceARN === countsStreamArn);
|
|
59
|
-
|
|
60
|
-
const references = referenceRecords.flatMap(record => {
|
|
61
|
-
const state = parseDynamoDbStreamRecordState(record);
|
|
62
|
-
switch (state.TAG) {
|
|
63
|
-
case 0: { // NewImage(id, newImage)
|
|
64
|
-
const id = state._0;
|
|
65
|
-
let inc;
|
|
66
|
-
try {
|
|
67
|
-
inc = parseJsonOrThrow(state._1, referencesViewSchema).inc;
|
|
68
|
-
} catch (_) {
|
|
69
|
-
inc = 1;
|
|
70
|
-
}
|
|
71
|
-
return [[id, inc]];
|
|
72
|
-
}
|
|
73
|
-
case 2: // NewAndOldImage — duplicate
|
|
74
|
-
log.debug("ignoring duplicate id: " + state._0, { comp: "CounterEntryPoint" });
|
|
75
|
-
return [];
|
|
76
|
-
default:
|
|
77
|
-
return [];
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const counts = countRecords.flatMap(record => {
|
|
82
|
-
const state = parseDynamoDbStreamRecordState(record);
|
|
83
|
-
if (state.TAG === 0 || state.TAG === 2) {
|
|
84
|
-
return [state._1];
|
|
85
|
-
}
|
|
86
|
-
return [];
|
|
87
|
-
});
|
|
33
|
+
const initPromise = build();
|
|
88
34
|
|
|
89
|
-
|
|
90
|
-
return
|
|
35
|
+
export async function handler(event, context) {
|
|
36
|
+
return (await initPromise)(event, context);
|
|
91
37
|
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Typed cold-start core for the Counter Lambda entry point.
|
|
2
|
+
//
|
|
3
|
+
// The "typed core, thin shell" split (docs/plans/minimize-lambda-entrypoint-mjs-shell.md):
|
|
4
|
+
// CounterEntryPoint.mjs keeps only the untyped seam — the dynamic `import()`
|
|
5
|
+
// of the target-spec/mappings modules named in HANDLER_CONFIG, the
|
|
6
|
+
// `patchSpecId` fix-up, and the EventMapper_Callback.MakeCounterHandler
|
|
7
|
+
// functor application consuming them. HANDLER_CONFIG parsing, the
|
|
8
|
+
// Counter_Callback.Make application (a functor over an inline module capturing
|
|
9
|
+
// runtime values), and the references/counts stream routing (the runtime twin
|
|
10
|
+
// of the deploy-time CounterHandler_DynamoDbStream_Runtime.handleStreamEvent,
|
|
11
|
+
// over plain ARN strings instead of Pulumi resources) live here, fully
|
|
12
|
+
// type-checked.
|
|
13
|
+
//
|
|
14
|
+
// Two shapes the former shell got wrong are repaired here:
|
|
15
|
+
// - It read `config.publishQueueUrl`, but the deploy side
|
|
16
|
+
// (CounterHandler_DynamoDbStream.res) writes `publishChannelId` — the
|
|
17
|
+
// CountFinished publish went to an undefined queue URL.
|
|
18
|
+
// - Its queryEngine stub had `query`/`queryAll` fields where
|
|
19
|
+
// QueryEngine.operations needs `scan`/`query`.
|
|
20
|
+
|
|
21
|
+
type handlerConfig = {
|
|
22
|
+
targetSpecModule?: string,
|
|
23
|
+
mappingsModule?: string,
|
|
24
|
+
countsTableName?: string,
|
|
25
|
+
// The publish address of the target's command topic (SQS queue URL) — the
|
|
26
|
+
// field name the deploy side actually writes.
|
|
27
|
+
publishChannelId?: string,
|
|
28
|
+
referencesStreamArn?: string,
|
|
29
|
+
countsStreamArn?: string,
|
|
30
|
+
}
|
|
31
|
+
@val @scope("JSON") external jsonParse: string => handlerConfig = "parse"
|
|
32
|
+
// A real binding (not a bare external) so the shell can import it.
|
|
33
|
+
let parseHandlerConfig = (raw: string): handlerConfig => jsonParse(raw)
|
|
34
|
+
|
|
35
|
+
// ── Counter-handler operations (third argument of MakeCounterHandler) ───────
|
|
36
|
+
// The query engine is not available in the bundled handler; both operations
|
|
37
|
+
// silently return [] (the former shell's stub intent).
|
|
38
|
+
|
|
39
|
+
let makeCounterOps = (config: handlerConfig): EventMapperEntryPoint_Ops.counterOps => {
|
|
40
|
+
let queueUrl = config.publishChannelId->Option.getOr("")
|
|
41
|
+
let queue: Util_SQS_Runtime.resolvedQueue = {id: queueUrl, name: queueUrl, arn: ""}
|
|
42
|
+
{
|
|
43
|
+
publishJsons: queue->CommandTopicChannel_SQS_Runtime.publishJsons(AWS.SQS_FIFO),
|
|
44
|
+
queryEngine: {
|
|
45
|
+
scan: async (~readModelName as _, ~filterConfigs as _, ~limit as _) => [],
|
|
46
|
+
query: async (
|
|
47
|
+
~readModelName as _,
|
|
48
|
+
~key as _=?,
|
|
49
|
+
~id as _,
|
|
50
|
+
~subIdConfig as _=?,
|
|
51
|
+
~filterConfigs as _=?,
|
|
52
|
+
~ascending as _=?,
|
|
53
|
+
~limit as _=?,
|
|
54
|
+
) => [],
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ── Stream routing ──────────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
// The references view rows carry the increment to apply: {id, inc}.
|
|
62
|
+
@schema
|
|
63
|
+
type referencesView = {
|
|
64
|
+
id: string,
|
|
65
|
+
inc: int,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Pure routing: split a mixed stream batch into reference increments and
|
|
69
|
+
// count rows, keyed by the two source ARNs. Records from other sources are
|
|
70
|
+
// dropped silently (the former shell's behavior).
|
|
71
|
+
let splitRecords = (
|
|
72
|
+
~referencesStreamArn: string,
|
|
73
|
+
~countsStreamArn: string,
|
|
74
|
+
records: array<PulumiAws.DynamoDb.Stream.record>,
|
|
75
|
+
): (array<(string, int)>, array<JSON.t>) => {
|
|
76
|
+
let dynamoDbRecords =
|
|
77
|
+
records->Array.filter(record =>
|
|
78
|
+
record.eventSource == "aws:dynamodb" &&
|
|
79
|
+
(record.eventSourceARN == referencesStreamArn ||
|
|
80
|
+
record.eventSourceARN == countsStreamArn)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
let (referenceRecords, countRecords) =
|
|
84
|
+
dynamoDbRecords->Array.partition(record => record.eventSourceARN == referencesStreamArn)
|
|
85
|
+
|
|
86
|
+
let references = referenceRecords->Array.filterMap(record =>
|
|
87
|
+
switch record->Util_DynamoDbStream_Runtime.parseDynamoDbStreamRecordState {
|
|
88
|
+
| NewImage(id, newImage) =>
|
|
89
|
+
let inc = switch newImage->S.parseJsonOrThrow(referencesViewSchema) {
|
|
90
|
+
| {inc} => inc
|
|
91
|
+
| exception _ => 1
|
|
92
|
+
}
|
|
93
|
+
Some((id, inc))
|
|
94
|
+
| NewAndOldImage(id, _, _) =>
|
|
95
|
+
StreamRoutedEntryPoint_Ops.logDebug(
|
|
96
|
+
"ignoring duplicate id: " ++ id,
|
|
97
|
+
{comp: "CounterEntryPoint"},
|
|
98
|
+
)
|
|
99
|
+
None
|
|
100
|
+
| _ => None
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
let counts = countRecords->Array.filterMap(record =>
|
|
105
|
+
switch record->Util_DynamoDbStream_Runtime.parseDynamoDbStreamRecordState {
|
|
106
|
+
| NewImage(_, newImage) | NewAndOldImage(_, newImage, _) => Some(newImage)
|
|
107
|
+
| _ => None
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
(references, counts)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let makeHandler = (
|
|
115
|
+
config: handlerConfig,
|
|
116
|
+
jsonEventsHandler: ReventlessCore.Counter.jsonEventsHandler,
|
|
117
|
+
) => {
|
|
118
|
+
module Callback = ReventlessCore.Counter_Callback.Make({
|
|
119
|
+
let name = "BundledCounter"
|
|
120
|
+
let countsDbCount = QueryDbStorage_DynamoDb_Runtime.count(
|
|
121
|
+
(
|
|
122
|
+
{
|
|
123
|
+
id: config.countsTableName->Option.getOr(""),
|
|
124
|
+
name: config.countsTableName->Option.getOr(""),
|
|
125
|
+
arn: "",
|
|
126
|
+
hashKey: "id",
|
|
127
|
+
}: Util_DynamoDb_Runtime.resolvedTable
|
|
128
|
+
),
|
|
129
|
+
)
|
|
130
|
+
let jsonEventsHandler = jsonEventsHandler
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
let referencesStreamArn = config.referencesStreamArn->Option.getOr("")
|
|
134
|
+
let countsStreamArn = config.countsStreamArn->Option.getOr("")
|
|
135
|
+
|
|
136
|
+
async (event: PulumiAws.DynamoDb.Stream.event, _context: PulumiAws.Lambda.context) => {
|
|
137
|
+
let (references, counts) = splitRecords(
|
|
138
|
+
~referencesStreamArn,
|
|
139
|
+
~countsStreamArn,
|
|
140
|
+
event.records,
|
|
141
|
+
)
|
|
142
|
+
await Callback.counterHandler(~references, ~counts)
|
|
143
|
+
""
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
5
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
|
+
import * as Counter_Callback$ReventlessCore from "@reventlessdev/reventless-core/src/components/Counter/Counter_Callback.res.mjs";
|
|
7
|
+
import * as StreamRoutedEntryPoint_Ops$ReventlessAws from "./StreamRoutedEntryPoint_Ops.res.mjs";
|
|
8
|
+
import * as Util_DynamoDbStream_Runtime$ReventlessAws from "../../util/Util_DynamoDbStream_Runtime.res.mjs";
|
|
9
|
+
import * as CommandTopicChannel_SQS_Runtime$ReventlessAws from "../CommandTopic/CommandTopicChannel_SQS_Runtime.res.mjs";
|
|
10
|
+
import * as QueryDbStorage_DynamoDb_Runtime$ReventlessAws from "../QueryDb/QueryDbStorage_DynamoDb_Runtime.res.mjs";
|
|
11
|
+
|
|
12
|
+
function parseHandlerConfig(raw) {
|
|
13
|
+
return JSON.parse(raw);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function makeCounterOps(config) {
|
|
17
|
+
let queueUrl = Stdlib_Option.getOr(config.publishChannelId, "");
|
|
18
|
+
let queue = {
|
|
19
|
+
id: queueUrl,
|
|
20
|
+
name: queueUrl,
|
|
21
|
+
arn: ""
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
publishJsons: CommandTopicChannel_SQS_Runtime$ReventlessAws.publishJsons(queue, "SQS_FIFO"),
|
|
25
|
+
queryEngine: {
|
|
26
|
+
scan: async (param, param$1, param$2) => [],
|
|
27
|
+
query: async (param, param$1, param$2, param$3, param$4, param$5, param$6) => []
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let referencesViewSchema = S.schema(s => ({
|
|
33
|
+
id: s.m(S.string),
|
|
34
|
+
inc: s.m(S.int)
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
function splitRecords(referencesStreamArn, countsStreamArn, records) {
|
|
38
|
+
let dynamoDbRecords = records.filter(record => {
|
|
39
|
+
if (record.eventSource === "aws:dynamodb") {
|
|
40
|
+
if (record.eventSourceARN === referencesStreamArn) {
|
|
41
|
+
return true;
|
|
42
|
+
} else {
|
|
43
|
+
return record.eventSourceARN === countsStreamArn;
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
let match = Stdlib_Array.partition(dynamoDbRecords, record => record.eventSourceARN === referencesStreamArn);
|
|
50
|
+
let references = Stdlib_Array.filterMap(match[0], record => {
|
|
51
|
+
let match = Util_DynamoDbStream_Runtime$ReventlessAws.parseDynamoDbStreamRecordState(record);
|
|
52
|
+
if (typeof match !== "object") {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
switch (match.TAG) {
|
|
56
|
+
case "NewImage" :
|
|
57
|
+
let inc;
|
|
58
|
+
let exit = 0;
|
|
59
|
+
let val;
|
|
60
|
+
try {
|
|
61
|
+
val = S.parseJsonOrThrow(match._1, referencesViewSchema);
|
|
62
|
+
exit = 1;
|
|
63
|
+
} catch (exn) {
|
|
64
|
+
inc = 1;
|
|
65
|
+
}
|
|
66
|
+
if (exit === 1) {
|
|
67
|
+
inc = val.inc;
|
|
68
|
+
}
|
|
69
|
+
return [
|
|
70
|
+
match._0,
|
|
71
|
+
inc
|
|
72
|
+
];
|
|
73
|
+
case "OldImage" :
|
|
74
|
+
return;
|
|
75
|
+
case "NewAndOldImage" :
|
|
76
|
+
StreamRoutedEntryPoint_Ops$ReventlessAws.logDebug("ignoring duplicate id: " + match._0, {
|
|
77
|
+
comp: "CounterEntryPoint"
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
let counts = Stdlib_Array.filterMap(match[1], record => {
|
|
83
|
+
let match = Util_DynamoDbStream_Runtime$ReventlessAws.parseDynamoDbStreamRecordState(record);
|
|
84
|
+
if (typeof match !== "object") {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
switch (match.TAG) {
|
|
88
|
+
case "OldImage" :
|
|
89
|
+
return;
|
|
90
|
+
case "NewImage" :
|
|
91
|
+
case "NewAndOldImage" :
|
|
92
|
+
return match._1;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
return [
|
|
96
|
+
references,
|
|
97
|
+
counts
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function makeHandler(config, jsonEventsHandler) {
|
|
102
|
+
let countsDbCount = QueryDbStorage_DynamoDb_Runtime$ReventlessAws.count({
|
|
103
|
+
id: Stdlib_Option.getOr(config.countsTableName, ""),
|
|
104
|
+
name: Stdlib_Option.getOr(config.countsTableName, ""),
|
|
105
|
+
arn: "",
|
|
106
|
+
hashKey: "id"
|
|
107
|
+
});
|
|
108
|
+
let Callback = Counter_Callback$ReventlessCore.Make({
|
|
109
|
+
name: "BundledCounter",
|
|
110
|
+
countsDbCount: countsDbCount,
|
|
111
|
+
jsonEventsHandler: jsonEventsHandler
|
|
112
|
+
});
|
|
113
|
+
let referencesStreamArn = Stdlib_Option.getOr(config.referencesStreamArn, "");
|
|
114
|
+
let countsStreamArn = Stdlib_Option.getOr(config.countsStreamArn, "");
|
|
115
|
+
return async (event, _context) => {
|
|
116
|
+
let match = splitRecords(referencesStreamArn, countsStreamArn, event.Records);
|
|
117
|
+
await Callback.counterHandler(match[0], match[1]);
|
|
118
|
+
return "";
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export {
|
|
123
|
+
parseHandlerConfig,
|
|
124
|
+
makeCounterOps,
|
|
125
|
+
referencesViewSchema,
|
|
126
|
+
splitRecords,
|
|
127
|
+
makeHandler,
|
|
128
|
+
}
|
|
129
|
+
/* referencesViewSchema Not a pure module */
|
|
@@ -269,7 +269,17 @@ let buildInboundReceiver = (
|
|
|
269
269
|
try {
|
|
270
270
|
let _ = await ops.save(id, json, ReventlessCore.QueryDb.Overwrite, None)
|
|
271
271
|
} catch {
|
|
272
|
-
|
|
|
272
|
+
| exn =>
|
|
273
|
+
// A failed audit write must not fail the mutation (the command was
|
|
274
|
+
// already published), but it must not vanish either: an AccessDenied
|
|
275
|
+
// here means the command Lambda's role lacks PutItem on the audit table,
|
|
276
|
+
// which otherwise surfaces only as a permanently empty audit view.
|
|
277
|
+
let detail =
|
|
278
|
+
exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown error")
|
|
279
|
+
ReventlessCore.EffectLogger.logError(
|
|
280
|
+
~comp="InboundTranslationSlice.audit",
|
|
281
|
+
`failed to persist audit row ${id}: ${detail}`,
|
|
282
|
+
)->Effect.runSync
|
|
273
283
|
}
|
|
274
284
|
})
|
|
275
285
|
| None => ()
|
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
import * as S from "sury/src/S.res.mjs";
|
|
4
4
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
5
|
+
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
5
6
|
import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
|
|
6
7
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
8
|
import * as Effect from "effect/Effect";
|
|
8
9
|
import * as Stream from "effect/Stream";
|
|
9
10
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
10
11
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
12
|
+
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
11
13
|
import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
|
|
14
|
+
import * as EffectLogger$ReventlessCore from "@reventlessdev/reventless-core/src/util/EffectLogger.res.mjs";
|
|
12
15
|
import * as CommandTopic_Helpers$ReventlessCore from "@reventlessdev/reventless-core/src/components/CommandTopic/CommandTopic_Helpers.res.mjs";
|
|
13
16
|
import * as InboundTranslationSlice_Callback$ReventlessCore from "@reventlessdev/reventless-core/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs";
|
|
14
17
|
import * as DcbEventLogStorage_DynamoDb_Runtime$ReventlessAws from "../DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res.mjs";
|
|
@@ -105,13 +108,16 @@ function buildInboundReceiver(spec, translation, publishJsons, auditQueryDbOps)
|
|
|
105
108
|
if (auditQueryDbOps !== undefined) {
|
|
106
109
|
let rows = Object.entries(callback.auditLog);
|
|
107
110
|
await Stdlib_Array.reduce(rows, Promise.resolve(), async (prev, param) => {
|
|
111
|
+
let id = param[0];
|
|
108
112
|
await prev;
|
|
109
113
|
let json = S.reverseConvertToJsonOrThrow(param[1], InboundTranslationSlice_Callback$ReventlessCore.auditRowSchema);
|
|
110
114
|
try {
|
|
111
|
-
await auditQueryDbOps.save(
|
|
112
|
-
return;
|
|
113
|
-
} catch (exn) {
|
|
115
|
+
await auditQueryDbOps.save(id, json, "Overwrite", undefined);
|
|
114
116
|
return;
|
|
117
|
+
} catch (raw_exn) {
|
|
118
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
119
|
+
let detail = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "unknown error");
|
|
120
|
+
return Effect.runSync(EffectLogger$ReventlessCore.logError("InboundTranslationSlice.audit", undefined, `failed to persist audit row ` + id + `: ` + detail));
|
|
115
121
|
}
|
|
116
122
|
});
|
|
117
123
|
}
|