@reventlessdev/reventless-aws 3.0.0-alpha.271 → 3.0.0-alpha.273
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 +19 -0
- package/package.json +9 -8
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +20 -16
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res.mjs +7 -7
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +14 -5
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res.mjs +10 -3
- package/src/adapter/Api/Platform_UIFragments_Lambda.res +15 -13
- package/src/adapter/Api/Platform_UIFragments_Lambda.res.mjs +3 -2
- package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res +8 -1
- package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res.mjs +3 -2
- package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res +15 -13
- package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res.mjs +3 -2
- package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +6 -12
- package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res.mjs +4 -8
- package/src/adapter/QueryDb/QueryInterceptor_Provisioning.res +155 -0
- package/src/adapter/QueryDb/QueryInterceptor_Provisioning.res.mjs +92 -0
- package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +4 -9
- package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res.mjs +8 -2
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +32 -62
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res.mjs +7 -20
- package/src/adapter/StateTopic/StateTopic_AppSync.res +15 -13
- package/src/adapter/StateTopic/StateTopic_AppSync.res.mjs +3 -2
- package/src/adapter/Upload/Upload_Claim_S3.res +15 -13
- package/src/adapter/Upload/Upload_Claim_S3.res.mjs +3 -2
- package/src/adapter/Upload/Upload_Presign_S3.res +15 -13
- package/src/adapter/Upload/Upload_Presign_S3.res.mjs +3 -2
- package/src/components/Api/AppSync_Adapter.res +13 -9
- package/src/components/Api/AppSync_Adapter.res.mjs +4 -3
- package/src/util/Util_LambdaLogging.res +69 -21
- package/src/util/Util_LambdaLogging.res.mjs +21 -8
- package/src/util/Util_LogGroup_Adopting.res +480 -0
- package/src/util/Util_LogGroup_Adopting.res.mjs +365 -0
- package/src/util/Util_LogGroup_Adopting_Js.mjs +20 -0
- package/src/util/Util_LogRetention.res +11 -12
- package/tests/Util_LambdaLoggingTest.res +36 -0
- package/tests/Util_LambdaLoggingTest.res.mjs +22 -0
- package/tests/Util_LogGroup_AdoptingTest.res +169 -0
- package/tests/Util_LogGroup_AdoptingTest.res.mjs +208 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Aws from "@pulumi/aws";
|
|
4
|
+
import * as IAM$PulumiAws from "@reventlessdev/rescript-pulumi-aws/src/IAM/IAM.res.mjs";
|
|
5
|
+
import * as Output$Pulumi from "@reventlessdev/rescript-pulumi-pulumi/src/Output.res.mjs";
|
|
6
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
|
+
import * as Pulumi from "@pulumi/pulumi";
|
|
8
|
+
import * as AWS$ReventlessAws from "../AWS.res.mjs";
|
|
9
|
+
import * as AWS_Tags$ReventlessAws from "../AWS_Tags.res.mjs";
|
|
10
|
+
import * as PolicyDocument$PulumiAws from "@reventlessdev/rescript-pulumi-aws/src/IAM/PolicyDocument.res.mjs";
|
|
11
|
+
import * as Util_Bundle$ReventlessAws from "../../util/Util_Bundle.res.mjs";
|
|
12
|
+
import * as QueryInterception$ReventlessCore from "@reventlessdev/reventless-core/src/adapter/QueryInterception/QueryInterception.res.mjs";
|
|
13
|
+
import * as ResourceAttribution$ReventlessCore from "@reventlessdev/reventless-core/src/ResourceAttribution.res.mjs";
|
|
14
|
+
import * as RuntimeEnvironment_Lambda$ReventlessAws from "../Runtime/RuntimeEnvironment_Lambda.res.mjs";
|
|
15
|
+
|
|
16
|
+
let byApi = new Map();
|
|
17
|
+
|
|
18
|
+
let namesUsed = {};
|
|
19
|
+
|
|
20
|
+
function nameFor() {
|
|
21
|
+
let owner = Stdlib_Option.getOr(ResourceAttribution$ReventlessCore.current.contents.plugin, "Platform");
|
|
22
|
+
let used = Stdlib_Option.getOr(namesUsed[owner], 0);
|
|
23
|
+
namesUsed[owner] = used + 1 | 0;
|
|
24
|
+
if (used === 0) {
|
|
25
|
+
return owner + "QueryInterceptor";
|
|
26
|
+
} else {
|
|
27
|
+
return owner + "QueryInterceptor" + (used + 1 | 0).toString();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function buildInterceptor(api, opts) {
|
|
32
|
+
let name = nameFor();
|
|
33
|
+
let componentOpts_parent = opts.parent;
|
|
34
|
+
let componentOpts = {
|
|
35
|
+
parent: componentOpts_parent
|
|
36
|
+
};
|
|
37
|
+
let packageDirs = Object.fromEntries([[
|
|
38
|
+
"@reventlessdev/reventless-aws",
|
|
39
|
+
Util_Bundle$ReventlessAws.resolvePackageRoot(undefined, "@reventlessdev/reventless-aws")
|
|
40
|
+
]]);
|
|
41
|
+
let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/QueryDb/QueryInterceptor_Lambda.res.mjs", packageDirs, undefined, undefined);
|
|
42
|
+
let runtime = RuntimeEnvironment_Lambda$ReventlessAws.makeFromCodeAsset(name, {
|
|
43
|
+
TAG: "Other",
|
|
44
|
+
_0: "QueryInterceptor"
|
|
45
|
+
}, "Plugin", match.code, match.sourceCodeHash, undefined, 256, 10, undefined, undefined, undefined, undefined, undefined, componentOpts);
|
|
46
|
+
let lambdaArn = Output$Pulumi.flatMap(runtime.parts.lambda, lambda => lambda.arn);
|
|
47
|
+
let dataSourceRole = IAM$PulumiAws.Role.makeWithDefaultPolicy(name + "DataSource", Pulumi.output(AWS$ReventlessAws.AppSync.principal), AWS_Tags$ReventlessAws.make(name + "DataSource", "Plugin", "Identity", "Plugin", undefined, undefined, undefined, undefined), opts);
|
|
48
|
+
Pulumi.all([
|
|
49
|
+
lambdaArn,
|
|
50
|
+
dataSourceRole.id
|
|
51
|
+
]).apply(param => {
|
|
52
|
+
new (Aws.iam.RolePolicy)(name + "DataSource", {
|
|
53
|
+
policy: PolicyDocument$PulumiAws.toJsonString(PolicyDocument$PulumiAws.make(undefined, name + "DataSourcePolicy", [{
|
|
54
|
+
Sid: "AllowDataSourceInvokeInterceptor",
|
|
55
|
+
Effect: "Allow",
|
|
56
|
+
Action: "lambda:InvokeFunction",
|
|
57
|
+
Resource: param[0]
|
|
58
|
+
}])),
|
|
59
|
+
role: param[1]
|
|
60
|
+
}, opts);
|
|
61
|
+
});
|
|
62
|
+
return new (Aws.appsync.DataSource)(name + "DataSource", {
|
|
63
|
+
type: "AWS_LAMBDA",
|
|
64
|
+
apiId: Output$Pulumi.flatMap(api, api => api.id),
|
|
65
|
+
lambdaConfig: {
|
|
66
|
+
functionArn: lambdaArn
|
|
67
|
+
},
|
|
68
|
+
serviceRoleArn: dataSourceRole.arn
|
|
69
|
+
}, opts).name;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function dataSourceName(api, opts) {
|
|
73
|
+
if (!QueryInterception$ReventlessCore.isEnabled()) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
let existing = byApi.get(api);
|
|
77
|
+
if (existing !== undefined) {
|
|
78
|
+
return existing;
|
|
79
|
+
}
|
|
80
|
+
let created = buildInterceptor(api, opts);
|
|
81
|
+
byApi.set(api, created);
|
|
82
|
+
return created;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
byApi,
|
|
87
|
+
namesUsed,
|
|
88
|
+
nameFor,
|
|
89
|
+
buildInterceptor,
|
|
90
|
+
dataSourceName,
|
|
91
|
+
}
|
|
92
|
+
/* byApi Not a pure module */
|
|
@@ -659,12 +659,9 @@ let warnSkippedExtension = (ext: extensionConfig) =>
|
|
|
659
659
|
// ── Asset files (bundled alongside index.mjs in the code archive) ───────────
|
|
660
660
|
// pluginDefinition is shipped as a file rather than packed into HANDLER_CONFIG
|
|
661
661
|
// (UpdateFunctionConfiguration has a 5120-byte limit; pluginStructure alone blew
|
|
662
|
-
// past it). process.cwd() is /var/task in Lambda,
|
|
663
|
-
// against the extracted zip.
|
|
662
|
+
// past it). process.cwd() is /var/task in Lambda, where the archive is extracted.
|
|
664
663
|
|
|
665
|
-
|
|
666
|
-
@new external makeUrl: (string, string) => url = "URL"
|
|
667
|
-
@module("node:fs") external readFileSyncUrl: (url, string) => string = "readFileSync"
|
|
664
|
+
let assetPath = (fileName: string): string => NodePath.join([NodeProcess.cwd(), fileName])
|
|
668
665
|
|
|
669
666
|
// pluginDefinition.json is written at deploy time as a stable JSON literal
|
|
670
667
|
// matching Reventless.Plugin.pluginDefinitionSchema (PluginRuntime_Builder), so
|
|
@@ -675,9 +672,7 @@ external asPluginDefinition: JSON.t => Reventless.Plugin.pluginDefinition = "%id
|
|
|
675
672
|
|
|
676
673
|
let loadPluginDefinition = (): Reventless.Plugin.pluginDefinition =>
|
|
677
674
|
try {
|
|
678
|
-
|
|
679
|
-
->JSON.parseOrThrow
|
|
680
|
-
->asPluginDefinition
|
|
675
|
+
assetPath("pluginDefinition.json")->NodeFs.readFileSync->JSON.parseOrThrow->asPluginDefinition
|
|
681
676
|
} catch {
|
|
682
677
|
| exn =>
|
|
683
678
|
JsError.throwWithMessage(
|
|
@@ -691,7 +686,7 @@ let loadPluginDefinition = (): Reventless.Plugin.pluginDefinition =>
|
|
|
691
686
|
// both map to None.
|
|
692
687
|
let loadUiFragments = (): option<JSON.t> =>
|
|
693
688
|
try {
|
|
694
|
-
switch
|
|
689
|
+
switch assetPath("uiFragments.json")->NodeFs.readFileSync->JSON.parseOrThrow {
|
|
695
690
|
| JSON.Null => None
|
|
696
691
|
| json => Some(json)
|
|
697
692
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Nodefs from "node:fs";
|
|
4
|
+
import * as Nodepath from "node:path";
|
|
4
5
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
5
6
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
6
7
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
@@ -515,9 +516,13 @@ function warnSkippedExtension(ext) {
|
|
|
515
516
|
});
|
|
516
517
|
}
|
|
517
518
|
|
|
519
|
+
function assetPath(fileName) {
|
|
520
|
+
return Nodepath.join(process.cwd(), fileName);
|
|
521
|
+
}
|
|
522
|
+
|
|
518
523
|
function loadPluginDefinition() {
|
|
519
524
|
try {
|
|
520
|
-
return JSON.parse(Nodefs.readFileSync(
|
|
525
|
+
return JSON.parse(Nodefs.readFileSync(assetPath("pluginDefinition.json"), "utf8"));
|
|
521
526
|
} catch (raw_exn) {
|
|
522
527
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
523
528
|
return Stdlib_JsError.throwWithMessage("Failed to load pluginDefinition.json from asset zip: " + exnMessage(exn));
|
|
@@ -526,7 +531,7 @@ function loadPluginDefinition() {
|
|
|
526
531
|
|
|
527
532
|
function loadUiFragments() {
|
|
528
533
|
try {
|
|
529
|
-
let json = JSON.parse(Nodefs.readFileSync(
|
|
534
|
+
let json = JSON.parse(Nodefs.readFileSync(assetPath("uiFragments.json"), "utf8"));
|
|
530
535
|
if (json === null) {
|
|
531
536
|
return;
|
|
532
537
|
} else {
|
|
@@ -642,6 +647,7 @@ export {
|
|
|
642
647
|
buildPublishToAggregates,
|
|
643
648
|
extensionPublishDicts,
|
|
644
649
|
warnSkippedExtension,
|
|
650
|
+
assetPath,
|
|
645
651
|
loadPluginDefinition,
|
|
646
652
|
loadUiFragments,
|
|
647
653
|
pushHandler,
|
|
@@ -145,17 +145,7 @@ let makeFromCodeAsset: (
|
|
|
145
145
|
let opts =
|
|
146
146
|
opts->Option.map(ReventlessCore.Util.Pulumi.ComponentResourceOptions.toCustomResourceOptions)
|
|
147
147
|
|
|
148
|
-
// The environment tier drives retention, default log level and whether the log
|
|
149
|
-
// group is Pulumi-managed. Resolved once from the stack name and the shared
|
|
150
|
-
// prod allow-list (the same notion of "production" that names the host-shell
|
|
151
|
-
// domain and the store layout).
|
|
152
148
|
let stack = Pulumi.Pulumi.getStackName()
|
|
153
|
-
let prodStacks = Util_HostUiDomain.resolveProdStacks()
|
|
154
|
-
// Stacks explicitly held on auto-created log groups pending a `pulumi import`
|
|
155
|
-
// (none today — the escape hatch for adopting a pre-existing stack later).
|
|
156
|
-
let unmanagedStacks = Util_LogRetention.parseUnmanagedStacks(
|
|
157
|
-
Util_LocalConfig.get("unmanagedLogGroupStacks")->Option.getOr(""),
|
|
158
|
-
)
|
|
159
149
|
|
|
160
150
|
// One attribution identity for every resource provisioned here: same owning
|
|
161
151
|
// component and kind throughout, distinct piece roles — the function itself,
|
|
@@ -285,6 +275,26 @@ let makeFromCodeAsset: (
|
|
|
285
275
|
variables->Dict.set("RUNTIME_EXTENSIONS", config->JSON.stringify->Pulumi.Input.make)
|
|
286
276
|
}
|
|
287
277
|
|
|
278
|
+
// Managed CloudWatch log group with explicit retention, created **before** the
|
|
279
|
+
// function so the function can be told to write to it. That ordering is what
|
|
280
|
+
// keeps the deploy the owner: a group created after its function races the
|
|
281
|
+
// auto-create that the function's first invocation triggers, and losing that
|
|
282
|
+
// race is permanent — the group persists, so every retry fails identically.
|
|
283
|
+
// Runtimes with a heartbeat, a stream subscription or a schedule are invoked
|
|
284
|
+
// within seconds of existing, so they lost it most reliably.
|
|
285
|
+
//
|
|
286
|
+
// Created when the caller pins `~logRetentionDays` (the app-developer opt-in)
|
|
287
|
+
// OR the stack manages its groups — every stack by default, bar any named in
|
|
288
|
+
// `unmanagedLogGroupStacks`. When neither holds, Lambda auto-creates an
|
|
289
|
+
// unmanaged group with no retention, as before.
|
|
290
|
+
let logGroup = Util_LambdaLogging.makeManagedLogGroup(
|
|
291
|
+
~name,
|
|
292
|
+
~retentionDaysOverride=?logRetentionDays,
|
|
293
|
+
~tags=tagsFor(~resourceName=`${name}LogGroup`, ~role=Logs),
|
|
294
|
+
~opts?,
|
|
295
|
+
(),
|
|
296
|
+
)
|
|
297
|
+
|
|
288
298
|
let tags = tagsFor(~resourceName=name, ~role=Runtime)
|
|
289
299
|
let lambda = Lambda.Function.make(
|
|
290
300
|
~name,
|
|
@@ -305,60 +315,20 @@ let makeFromCodeAsset: (
|
|
|
305
315
|
vpcConfig: ?vpcConfig,
|
|
306
316
|
environment: ({Lambda.Function.variables: variables}: Lambda.Function.functionEnvironment)
|
|
307
317
|
->Pulumi.Input.make,
|
|
318
|
+
// Points the function at the group above and, by reading its name output,
|
|
319
|
+
// orders the function after it.
|
|
320
|
+
loggingConfig: ?Util_LambdaLogging.loggingConfigFor(logGroup),
|
|
308
321
|
},
|
|
309
322
|
~opts?,
|
|
310
323
|
)
|
|
311
324
|
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
// `logRetentionDays` config key → the environment tier default.
|
|
320
|
-
//
|
|
321
|
-
// The group name derives from the function's *physical* name output, not the
|
|
322
|
-
// logical `name`. `Lambda.Function` has no `name` arg, so its physical name
|
|
323
|
-
// always carries Pulumi's `-<7hex>` suffix; a literal `/aws/lambda/${name}`
|
|
324
|
-
// would create an empty group beside the real one, leave orphan accumulation
|
|
325
|
-
// unchanged, and collide across stacks sharing an account.
|
|
326
|
-
let managedRetention = switch (
|
|
327
|
-
logRetentionDays,
|
|
328
|
-
Util_LogRetention.managesLogGroup(~stack, ~unmanagedStacks),
|
|
329
|
-
) {
|
|
330
|
-
| (Some(days), _) => Some(days)
|
|
331
|
-
| (None, true) =>
|
|
332
|
-
Some(
|
|
333
|
-
Util_LogRetention.retentionDaysFor(
|
|
334
|
-
~stack,
|
|
335
|
-
~prodStacks,
|
|
336
|
-
~configOverride=?Util_LocalConfig.get("logRetentionDays")->Option.flatMap(s =>
|
|
337
|
-
Int.fromString(s)
|
|
338
|
-
),
|
|
339
|
-
),
|
|
340
|
-
)
|
|
341
|
-
| (None, false) => None
|
|
342
|
-
}
|
|
343
|
-
managedRetention->Option.forEach(days => {
|
|
344
|
-
let logGroup = Cloudwatch.LogGroup.make(
|
|
345
|
-
~name=`${name}LogGroup`,
|
|
346
|
-
~args={
|
|
347
|
-
name: lambda.name
|
|
348
|
-
->Pulumi.Output.apply(n => `/aws/lambda/${n}`)
|
|
349
|
-
->Pulumi.Output.asInput,
|
|
350
|
-
retentionInDays: days->Pulumi.Input.make,
|
|
351
|
-
tags: tagsFor(~resourceName=`${name}LogGroup`, ~role=Logs),
|
|
352
|
-
},
|
|
353
|
-
~opts?,
|
|
354
|
-
)
|
|
355
|
-
|
|
356
|
-
// DCB command-handler Lambdas: extract the provider-neutral metric lines
|
|
357
|
-
// emitted by StateChangeSlice_Callback (`{reventlessMetric, slice, value}`)
|
|
358
|
-
// into CloudWatch metrics. Attached to the managed log group above so there
|
|
359
|
-
// is no race against Lambda's lazy auto-created group. Namespace/dimension
|
|
360
|
-
// are CloudWatch-specific and live here, not in core (provider-neutral).
|
|
361
|
-
if dcbMetrics {
|
|
325
|
+
// DCB command-handler Lambdas: extract the provider-neutral metric lines
|
|
326
|
+
// emitted by StateChangeSlice_Callback (`{reventlessMetric, slice, value}`)
|
|
327
|
+
// into CloudWatch metrics. Attached to the managed log group, which is the only
|
|
328
|
+
// group the function ever writes to. Namespace/dimension are CloudWatch-specific
|
|
329
|
+
// and live here, not in core (provider-neutral).
|
|
330
|
+
if dcbMetrics {
|
|
331
|
+
logGroup->Option.forEach(logGroup =>
|
|
362
332
|
Util_DcbMetrics.metricNames->Array.forEach(metricName => {
|
|
363
333
|
let _ = Cloudwatch.LogMetricFilter.make(
|
|
364
334
|
~name=`${name}${metricName}Filter`,
|
|
@@ -370,8 +340,8 @@ let makeFromCodeAsset: (
|
|
|
370
340
|
~opts?,
|
|
371
341
|
)
|
|
372
342
|
})
|
|
373
|
-
|
|
374
|
-
}
|
|
343
|
+
)
|
|
344
|
+
}
|
|
375
345
|
|
|
376
346
|
let lambdaResource = lambda->Util.Lambda.functionToResource(~tags=tags->Pulumi.Output.fromInput)
|
|
377
347
|
|
|
@@ -22,10 +22,7 @@ import * as Util_Pulumi$ReventlessCore from "@reventlessdev/reventless-core/src/
|
|
|
22
22
|
import * as Util_IAM_Role$ReventlessAws from "../../util/Util_IAM_Role.res.mjs";
|
|
23
23
|
import * as ComponentType$ReventlessCore from "@reventlessdev/reventless-core/src/ComponentType.res.mjs";
|
|
24
24
|
import * as Util_DcbMetrics$ReventlessAws from "../../util/Util_DcbMetrics.res.mjs";
|
|
25
|
-
import * as Util_LocalConfig$ReventlessAws from "../../util/Util_LocalConfig.res.mjs";
|
|
26
25
|
import * as RuntimeExtension$ReventlessCore from "@reventlessdev/reventless-core/src/adapter/RuntimeExtension/RuntimeExtension.res.mjs";
|
|
27
|
-
import * as Util_HostUiDomain$ReventlessAws from "../../util/Util_HostUiDomain.res.mjs";
|
|
28
|
-
import * as Util_LogRetention$ReventlessAws from "../../util/Util_LogRetention.res.mjs";
|
|
29
26
|
import * as Util_LambdaLogging$ReventlessAws from "../../util/Util_LambdaLogging.res.mjs";
|
|
30
27
|
import * as ResourceAttribution$ReventlessCore from "@reventlessdev/reventless-core/src/ResourceAttribution.res.mjs";
|
|
31
28
|
|
|
@@ -59,8 +56,6 @@ function makeFromCodeAsset(name, unitKind, componentKind, code, sourceCodeHash,
|
|
|
59
56
|
let dcbMetrics = dcbMetricsOpt !== undefined ? dcbMetricsOpt : false;
|
|
60
57
|
let opts$1 = Stdlib_Option.map(opts, Util_Pulumi$ReventlessCore.ComponentResourceOptions.toCustomResourceOptions);
|
|
61
58
|
let stack = Pulumi.getStack();
|
|
62
|
-
let prodStacks = Util_HostUiDomain$ReventlessAws.resolveProdStacks();
|
|
63
|
-
let unmanagedStacks = Util_LogRetention$ReventlessAws.parseUnmanagedStacks(Stdlib_Option.getOr(Util_LocalConfig$ReventlessAws.get("unmanagedLogGroupStacks"), ""));
|
|
64
59
|
let tagsFor = (resourceName, role) => AWS_Tags$ReventlessAws.make(resourceName, componentKind, role, undefined, name, undefined, undefined, undefined);
|
|
65
60
|
let lambdaRole = IAM$PulumiAws.Role.makeWithDefaultPolicy(name, Pulumi.output(AWS$ReventlessAws.Lambda.principal), tagsFor(name, "Identity"), opts$1);
|
|
66
61
|
Stdlib_Option.forEach(vpcConfig, param => {
|
|
@@ -136,6 +131,7 @@ function makeFromCodeAsset(name, unitKind, componentKind, code, sourceCodeHash,
|
|
|
136
131
|
]);
|
|
137
132
|
variables["RUNTIME_EXTENSIONS"] = JSON.stringify(config);
|
|
138
133
|
}
|
|
134
|
+
let logGroup = Util_LambdaLogging$ReventlessAws.makeManagedLogGroup(name, logRetentionDays, tagsFor(name + `LogGroup`, "Logs"), opts$1, undefined);
|
|
139
135
|
let tags = tagsFor(name, "Runtime");
|
|
140
136
|
let lambda = new (Aws.lambda.Function)(name, {
|
|
141
137
|
handler: "index.handler",
|
|
@@ -154,19 +150,11 @@ function makeFromCodeAsset(name, unitKind, componentKind, code, sourceCodeHash,
|
|
|
154
150
|
ephemeralStorage: Stdlib_Option.map(ephemeralStorageMb, mb => ({
|
|
155
151
|
size: mb
|
|
156
152
|
})),
|
|
157
|
-
vpcConfig: vpcConfig
|
|
153
|
+
vpcConfig: vpcConfig,
|
|
154
|
+
loggingConfig: Util_LambdaLogging$ReventlessAws.loggingConfigFor(logGroup)
|
|
158
155
|
}, opts$1 !== undefined ? Primitive_option.valFromOption(opts$1) : undefined);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
match$1 ? Util_LogRetention$ReventlessAws.retentionDaysFor(stack, prodStacks, Stdlib_Option.flatMap(Util_LocalConfig$ReventlessAws.get("logRetentionDays"), s => Stdlib_Int.fromString(s, undefined))) : undefined
|
|
162
|
-
);
|
|
163
|
-
Stdlib_Option.forEach(managedRetention, days => {
|
|
164
|
-
let logGroup = new (Aws.cloudwatch.LogGroup)(name + `LogGroup`, {
|
|
165
|
-
name: lambda.name.apply(n => `/aws/lambda/` + n),
|
|
166
|
-
retentionInDays: days,
|
|
167
|
-
tags: tagsFor(name + `LogGroup`, "Logs")
|
|
168
|
-
}, opts$1 !== undefined ? Primitive_option.valFromOption(opts$1) : undefined);
|
|
169
|
-
if (dcbMetrics) {
|
|
156
|
+
if (dcbMetrics) {
|
|
157
|
+
Stdlib_Option.forEach(logGroup, logGroup => {
|
|
170
158
|
Util_DcbMetrics$ReventlessAws.metricNames.forEach(metricName => {
|
|
171
159
|
new (Aws.cloudwatch.LogMetricFilter)(name + metricName + `Filter`, {
|
|
172
160
|
pattern: Util_DcbMetrics$ReventlessAws.patternFor(metricName),
|
|
@@ -174,9 +162,8 @@ function makeFromCodeAsset(name, unitKind, componentKind, code, sourceCodeHash,
|
|
|
174
162
|
metricTransformation: Util_DcbMetrics$ReventlessAws.transformationFor(metricName)
|
|
175
163
|
}, opts$1 !== undefined ? Primitive_option.valFromOption(opts$1) : undefined);
|
|
176
164
|
});
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
});
|
|
165
|
+
});
|
|
166
|
+
}
|
|
180
167
|
let lambdaResource = Util_Lambda$ReventlessAws.functionToResource(tags, lambda);
|
|
181
168
|
Monitoring$ReventlessCore.notify(unitKind, name, lambdaResource);
|
|
182
169
|
return {
|
|
@@ -218,6 +218,20 @@ let finish = (
|
|
|
218
218
|
|
|
219
219
|
let appsyncEndpoint = AppSync_EventsApi.httpEndpoint(eventsApi)
|
|
220
220
|
|
|
221
|
+
// Created before the function that writes to it — see
|
|
222
|
+
// `Util_LambdaLogging.makeManagedLogGroup` for why the ordering matters.
|
|
223
|
+
let logGroup = Util_LambdaLogging.makeManagedLogGroup(
|
|
224
|
+
~name=name ++ "StateTopicPublisher",
|
|
225
|
+
~tags=AWS.Tags.make(
|
|
226
|
+
~name=name ++ "StateTopicPublisherLogGroup",
|
|
227
|
+
~kind=ReventlessCore.QueryDb.componentType,
|
|
228
|
+
~role=Logs,
|
|
229
|
+
~component=name,
|
|
230
|
+
),
|
|
231
|
+
~opts,
|
|
232
|
+
(),
|
|
233
|
+
)
|
|
234
|
+
|
|
221
235
|
let lambda = Lambda.Function.make(
|
|
222
236
|
~name=name ++ "StateTopicPublisher",
|
|
223
237
|
~args={
|
|
@@ -242,23 +256,11 @@ let finish = (
|
|
|
242
256
|
]),
|
|
243
257
|
}: Lambda.Function.functionEnvironment
|
|
244
258
|
)->Pulumi.Input.make,
|
|
259
|
+
loggingConfig: ?Util_LambdaLogging.loggingConfigFor(logGroup),
|
|
245
260
|
},
|
|
246
261
|
~opts,
|
|
247
262
|
)
|
|
248
263
|
|
|
249
|
-
Util_LambdaLogging.makeManagedLogGroup(
|
|
250
|
-
~name=name ++ "StateTopicPublisher",
|
|
251
|
-
~lambdaName=lambda.name,
|
|
252
|
-
~tags=AWS.Tags.make(
|
|
253
|
-
~name=name ++ "StateTopicPublisherLogGroup",
|
|
254
|
-
~kind=ReventlessCore.QueryDb.componentType,
|
|
255
|
-
~role=Logs,
|
|
256
|
-
~component=name,
|
|
257
|
-
),
|
|
258
|
-
~opts,
|
|
259
|
-
(),
|
|
260
|
-
)
|
|
261
|
-
|
|
262
264
|
// One EventSourceMapping per stream, all targeting the shared Lambda.
|
|
263
265
|
// Retry posture: the handler throws on 5xx / network errors and logs-and-
|
|
264
266
|
// continues on 4xx. `maximumRetryAttempts: 3` bounds the per-record
|
|
@@ -90,6 +90,7 @@ function finish(eventsApi, opts) {
|
|
|
90
90
|
let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/StateTopic/StateTopic_AppSync_Ops.res.mjs", packageDirs, undefined, false);
|
|
91
91
|
let layers = Stdlib_Option.getOr(Stdlib_Option.map(Lambda$PulumiAws.reventlessLayerArn, arn => [arn]), []);
|
|
92
92
|
let appsyncEndpoint = AppSync_EventsApi$ReventlessAws.httpEndpoint(eventsApi);
|
|
93
|
+
let logGroup = Util_LambdaLogging$ReventlessAws.makeManagedLogGroup(name + "StateTopicPublisher", undefined, AWS_Tags$ReventlessAws.make(name + "StateTopicPublisherLogGroup", QueryDb$ReventlessCore.componentType, "Logs", undefined, name, undefined, undefined, undefined), opts, undefined);
|
|
93
94
|
let lambda = new (Aws.lambda.Function)(name + "StateTopicPublisher", {
|
|
94
95
|
handler: "index.handler",
|
|
95
96
|
runtime: "nodejs22.x",
|
|
@@ -124,9 +125,9 @@ function finish(eventsApi, opts) {
|
|
|
124
125
|
Util_LambdaLogging$ReventlessAws.logLevelEntry()
|
|
125
126
|
])
|
|
126
127
|
},
|
|
127
|
-
sourceCodeHash: match.sourceCodeHash
|
|
128
|
+
sourceCodeHash: match.sourceCodeHash,
|
|
129
|
+
loggingConfig: Util_LambdaLogging$ReventlessAws.loggingConfigFor(logGroup)
|
|
128
130
|
}, opts);
|
|
129
|
-
Util_LambdaLogging$ReventlessAws.makeManagedLogGroup(name + "StateTopicPublisher", lambda.name, AWS_Tags$ReventlessAws.make(name + "StateTopicPublisherLogGroup", QueryDb$ReventlessCore.componentType, "Logs", undefined, name, undefined, undefined, undefined), opts, undefined);
|
|
130
131
|
entries.forEach(entry => {
|
|
131
132
|
let esmName = entry.topicName + "Stream2" + name + "StateTopic";
|
|
132
133
|
new (Aws.lambda.EventSourceMapping)(esmName, {
|
|
@@ -266,6 +266,20 @@ let finish = (
|
|
|
266
266
|
->Option.getOr([])
|
|
267
267
|
->Pulumi.Input.make
|
|
268
268
|
|
|
269
|
+
// Created before the function that writes to it — see
|
|
270
|
+
// `Util_LambdaLogging.makeManagedLogGroup` for why the ordering matters.
|
|
271
|
+
let logGroup = Util_LambdaLogging.makeManagedLogGroup(
|
|
272
|
+
~name,
|
|
273
|
+
~tags=AWS.Tags.make(
|
|
274
|
+
~name=name ++ "LogGroup",
|
|
275
|
+
~kind=ReventlessCore.ComponentType.Plugin,
|
|
276
|
+
~role=Logs,
|
|
277
|
+
~component=name,
|
|
278
|
+
),
|
|
279
|
+
~opts,
|
|
280
|
+
(),
|
|
281
|
+
)
|
|
282
|
+
|
|
269
283
|
let lambda = Lambda.Function.make(
|
|
270
284
|
~name,
|
|
271
285
|
~args={
|
|
@@ -295,23 +309,11 @@ let finish = (
|
|
|
295
309
|
]),
|
|
296
310
|
}: Lambda.Function.functionEnvironment
|
|
297
311
|
)->Pulumi.Input.make,
|
|
312
|
+
loggingConfig: ?Util_LambdaLogging.loggingConfigFor(logGroup),
|
|
298
313
|
},
|
|
299
314
|
~opts,
|
|
300
315
|
)
|
|
301
316
|
|
|
302
|
-
Util_LambdaLogging.makeManagedLogGroup(
|
|
303
|
-
~name,
|
|
304
|
-
~lambdaName=lambda.name,
|
|
305
|
-
~tags=AWS.Tags.make(
|
|
306
|
-
~name=name ++ "LogGroup",
|
|
307
|
-
~kind=ReventlessCore.ComponentType.Plugin,
|
|
308
|
-
~role=Logs,
|
|
309
|
-
~component=name,
|
|
310
|
-
),
|
|
311
|
-
~opts,
|
|
312
|
-
(),
|
|
313
|
-
)
|
|
314
|
-
|
|
315
317
|
// One mapping per event log stream, all targeting the one Lambda.
|
|
316
318
|
// `maximumRetryAttempts` bounds a permanently failing record so it cannot
|
|
317
319
|
// wedge the shard — the default of -1 retries forever, which would turn one
|
|
@@ -125,6 +125,7 @@ function finish(plugin, stores, iteratorAgeAlarmMsOpt, opts) {
|
|
|
125
125
|
]]);
|
|
126
126
|
let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/Upload/Upload_Claim_S3_Ops.res.mjs", packageDirs, undefined, false);
|
|
127
127
|
let layers = Stdlib_Option.getOr(Stdlib_Option.map(Lambda$PulumiAws.reventlessLayerArn, arn => [arn]), []);
|
|
128
|
+
let logGroup = Util_LambdaLogging$ReventlessAws.makeManagedLogGroup(name, undefined, AWS_Tags$ReventlessAws.make(name + "LogGroup", "Plugin", "Logs", undefined, name, undefined, undefined, undefined), opts, undefined);
|
|
128
129
|
let lambda = new (Aws.lambda.Function)(name, {
|
|
129
130
|
handler: "index.handler",
|
|
130
131
|
runtime: "nodejs22.x",
|
|
@@ -159,9 +160,9 @@ function finish(plugin, stores, iteratorAgeAlarmMsOpt, opts) {
|
|
|
159
160
|
Util_LambdaLogging$ReventlessAws.logLevelEntry()
|
|
160
161
|
])
|
|
161
162
|
},
|
|
162
|
-
sourceCodeHash: match.sourceCodeHash
|
|
163
|
+
sourceCodeHash: match.sourceCodeHash,
|
|
164
|
+
loggingConfig: Util_LambdaLogging$ReventlessAws.loggingConfigFor(logGroup)
|
|
163
165
|
}, opts);
|
|
164
|
-
Util_LambdaLogging$ReventlessAws.makeManagedLogGroup(name, lambda.name, AWS_Tags$ReventlessAws.make(name + "LogGroup", "Plugin", "Logs", undefined, name, undefined, undefined, undefined), opts, undefined);
|
|
165
166
|
entries.forEach((entry, i) => {
|
|
166
167
|
let esmName = name + `Stream` + i.toString();
|
|
167
168
|
new (Aws.lambda.EventSourceMapping)(esmName, {
|
|
@@ -184,6 +184,20 @@ let make = (
|
|
|
184
184
|
->Option.getOr([])
|
|
185
185
|
->Pulumi.Input.make
|
|
186
186
|
|
|
187
|
+
// Created before the function that writes to it — see
|
|
188
|
+
// `Util_LambdaLogging.makeManagedLogGroup` for why the ordering matters.
|
|
189
|
+
let logGroup = Util_LambdaLogging.makeManagedLogGroup(
|
|
190
|
+
~name=name ++ "Lambda",
|
|
191
|
+
~tags=AWS.Tags.make(
|
|
192
|
+
~name=name ++ "LambdaLogGroup",
|
|
193
|
+
~kind=ReventlessCore.ComponentType.Platform,
|
|
194
|
+
~role=Logs,
|
|
195
|
+
~scope=Platform,
|
|
196
|
+
),
|
|
197
|
+
~opts,
|
|
198
|
+
(),
|
|
199
|
+
)
|
|
200
|
+
|
|
187
201
|
let lambda = Lambda.Function.make(
|
|
188
202
|
~name=name ++ "Lambda",
|
|
189
203
|
~args={
|
|
@@ -213,23 +227,11 @@ let make = (
|
|
|
213
227
|
]),
|
|
214
228
|
}: Lambda.Function.functionEnvironment
|
|
215
229
|
)->Pulumi.Input.make,
|
|
230
|
+
loggingConfig: ?Util_LambdaLogging.loggingConfigFor(logGroup),
|
|
216
231
|
},
|
|
217
232
|
~opts,
|
|
218
233
|
)
|
|
219
234
|
|
|
220
|
-
Util_LambdaLogging.makeManagedLogGroup(
|
|
221
|
-
~name=name ++ "Lambda",
|
|
222
|
-
~lambdaName=lambda.name,
|
|
223
|
-
~tags=AWS.Tags.make(
|
|
224
|
-
~name=name ++ "LambdaLogGroup",
|
|
225
|
-
~kind=ReventlessCore.ComponentType.Platform,
|
|
226
|
-
~role=Logs,
|
|
227
|
-
~scope=Platform,
|
|
228
|
-
),
|
|
229
|
-
~opts,
|
|
230
|
-
(),
|
|
231
|
-
)
|
|
232
|
-
|
|
233
235
|
let dataSourceRole = IAM.Role.makeWithDefaultPolicy(
|
|
234
236
|
~name=name ++ "DataSource",
|
|
235
237
|
~servicePrincipal=AWS.AppSync.principal->Pulumi.Output.make,
|
|
@@ -94,6 +94,7 @@ function make(api, stores, releaseWindowSecondsOpt, nameOpt, opts) {
|
|
|
94
94
|
]]);
|
|
95
95
|
let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/Upload/Upload_Presign_S3_Ops.res.mjs", packageDirs, undefined, false);
|
|
96
96
|
let layers = Stdlib_Option.getOr(Stdlib_Option.map(Lambda$PulumiAws.reventlessLayerArn, arn => [arn]), []);
|
|
97
|
+
let logGroup = Util_LambdaLogging$ReventlessAws.makeManagedLogGroup(name + "Lambda", undefined, AWS_Tags$ReventlessAws.make(name + "LambdaLogGroup", "Platform", "Logs", "Platform", undefined, undefined, undefined, undefined), opts$1, undefined);
|
|
97
98
|
let lambda = new (Aws.lambda.Function)(name + "Lambda", {
|
|
98
99
|
handler: "index.handler",
|
|
99
100
|
runtime: "nodejs22.x",
|
|
@@ -128,9 +129,9 @@ function make(api, stores, releaseWindowSecondsOpt, nameOpt, opts) {
|
|
|
128
129
|
Util_LambdaLogging$ReventlessAws.logLevelEntry()
|
|
129
130
|
])
|
|
130
131
|
},
|
|
131
|
-
sourceCodeHash: match.sourceCodeHash
|
|
132
|
+
sourceCodeHash: match.sourceCodeHash,
|
|
133
|
+
loggingConfig: Util_LambdaLogging$ReventlessAws.loggingConfigFor(logGroup)
|
|
132
134
|
}, opts$1);
|
|
133
|
-
Util_LambdaLogging$ReventlessAws.makeManagedLogGroup(name + "Lambda", lambda.name, AWS_Tags$ReventlessAws.make(name + "LambdaLogGroup", "Platform", "Logs", "Platform", undefined, undefined, undefined, undefined), opts$1, undefined);
|
|
134
135
|
let dataSourceRole = IAM$PulumiAws.Role.makeWithDefaultPolicy(name + "DataSource", Pulumi.output(AWS$ReventlessAws.AppSync.principal), AWS_Tags$ReventlessAws.make(name + "DataSource", "Platform", "Identity", "Platform", undefined, undefined, undefined, undefined), opts$1);
|
|
135
136
|
Pulumi.all([
|
|
136
137
|
lambda.arn,
|
|
@@ -552,19 +552,23 @@ let _makeApiResourceWith = (
|
|
|
552
552
|
// Managed log group with tiered retention for AppSync's own field-resolver logs,
|
|
553
553
|
// which land in `/aws/appsync/apis/<id>` and otherwise live forever with no
|
|
554
554
|
// retention. Managed on every stack by default (bar any in
|
|
555
|
-
// `unmanagedLogGroupStacks`), same as the Lambda groups.
|
|
556
|
-
//
|
|
557
|
-
//
|
|
555
|
+
// `unmanagedLogGroupStacks`), same as the Lambda groups.
|
|
556
|
+
//
|
|
557
|
+
// Unlike a Lambda's group this one cannot be created ahead of the resource that
|
|
558
|
+
// writes to it: the name comes from the API's server-assigned id, so the group
|
|
559
|
+
// is always second and any request the API serves in between creates it first.
|
|
560
|
+
// `Util_LogGroup_Adopting` is what makes losing that order survivable — it
|
|
561
|
+
// adopts an existing group rather than failing `ResourceAlreadyExists`.
|
|
558
562
|
let stack = Pulumi.Pulumi.getStackName()
|
|
559
563
|
let prodStacks = Util_HostUiDomain.resolveProdStacks()
|
|
560
564
|
let unmanagedStacks = Util_LogRetention.parseUnmanagedStacks(
|
|
561
565
|
Util_LocalConfig.get("unmanagedLogGroupStacks")->Option.getOr(""),
|
|
562
566
|
)
|
|
563
567
|
if Util_LogRetention.managesLogGroup(~stack, ~unmanagedStacks) {
|
|
564
|
-
let _ =
|
|
568
|
+
let _ = Util_LogGroup_Adopting.make(
|
|
565
569
|
~name=`${name}AppSyncLogGroup`,
|
|
566
|
-
~
|
|
567
|
-
|
|
570
|
+
~props={
|
|
571
|
+
logGroupName: graphQLApi.id
|
|
568
572
|
->Pulumi.Output.apply(id => `/aws/appsync/apis/${id}`)
|
|
569
573
|
->Pulumi.Output.asInput,
|
|
570
574
|
retentionInDays: Util_LogRetention.retentionDaysFor(
|
|
@@ -574,14 +578,14 @@ let _makeApiResourceWith = (
|
|
|
574
578
|
Int.fromString(s)
|
|
575
579
|
),
|
|
576
580
|
)->Pulumi.Input.make,
|
|
577
|
-
tags: AWS.Tags.
|
|
581
|
+
tags: AWS.Tags.makeDict(
|
|
578
582
|
~name=`${name}AppSyncLogGroup`,
|
|
579
583
|
~kind=ReventlessCore.ComponentType.Plugin,
|
|
580
584
|
~role=Logs,
|
|
581
585
|
~scope=Plugin,
|
|
582
|
-
),
|
|
586
|
+
)->Pulumi.Input.make,
|
|
583
587
|
},
|
|
584
|
-
~opts=customOpts,
|
|
588
|
+
~opts=Some(customOpts),
|
|
585
589
|
)
|
|
586
590
|
}
|
|
587
591
|
|
|
@@ -21,6 +21,7 @@ import * as GraphQL_Stitcher$ReventlessCore from "@reventlessdev/reventless-core
|
|
|
21
21
|
import * as Util_HostUiDomain$ReventlessAws from "../../util/Util_HostUiDomain.res.mjs";
|
|
22
22
|
import * as Util_LogRetention$ReventlessAws from "../../util/Util_LogRetention.res.mjs";
|
|
23
23
|
import * as AppSync_SdlDecorate$ReventlessAws from "./AppSync_SdlDecorate.res.mjs";
|
|
24
|
+
import * as Util_LogGroup_Adopting$ReventlessAws from "../../util/Util_LogGroup_Adopting.res.mjs";
|
|
24
25
|
import * as GraphQL_FragmentGenerator$ReventlessCore from "@reventlessdev/reventless-core/src/components/Api/GraphQL_FragmentGenerator.res.mjs";
|
|
25
26
|
|
|
26
27
|
let log = Logger$ReventlessCore.fromEnv();
|
|
@@ -316,10 +317,10 @@ function _makeApiResourceWith(name, schema, userPoolConfig, opts) {
|
|
|
316
317
|
let prodStacks = Util_HostUiDomain$ReventlessAws.resolveProdStacks();
|
|
317
318
|
let unmanagedStacks = Util_LogRetention$ReventlessAws.parseUnmanagedStacks(Stdlib_Option.getOr(Util_LocalConfig$ReventlessAws.get("unmanagedLogGroupStacks"), ""));
|
|
318
319
|
if (Util_LogRetention$ReventlessAws.managesLogGroup(stack, unmanagedStacks)) {
|
|
319
|
-
|
|
320
|
-
|
|
320
|
+
Util_LogGroup_Adopting$ReventlessAws.make(name + `AppSyncLogGroup`, {
|
|
321
|
+
logGroupName: graphQLApi.id.apply(id => `/aws/appsync/apis/` + id),
|
|
321
322
|
retentionInDays: Util_LogRetention$ReventlessAws.retentionDaysFor(stack, prodStacks, Stdlib_Option.flatMap(Util_LocalConfig$ReventlessAws.get("logRetentionDays"), s => Stdlib_Int.fromString(s, undefined))),
|
|
322
|
-
tags: AWS_Tags$ReventlessAws.
|
|
323
|
+
tags: AWS_Tags$ReventlessAws.makeDict(name + `AppSyncLogGroup`, "Plugin", "Logs", "Plugin", undefined, undefined, undefined, undefined)
|
|
323
324
|
}, customOpts);
|
|
324
325
|
}
|
|
325
326
|
return [
|