rds-database-auto-start-preventer 0.5.3 → 0.6.0
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/.jsii +64 -18
- package/API.md +84 -2
- package/README.md +40 -2
- package/assets/funcs/auto-start-prevent.lambda/index.js +3540 -939
- package/assets/funcs/auto-start-prevent.lambda/index.js.map +4 -4
- package/lib/funcs/auto-start-prevent.lambda.d.ts +1 -0
- package/lib/funcs/auto-start-prevent.lambda.js +132 -94
- package/lib/funcs/core/auto-start-prevent.predicates.d.ts +28 -9
- package/lib/funcs/core/auto-start-prevent.predicates.js +44 -17
- package/lib/rds-database-auto-start-prevent-stack.d.ts +1 -1
- package/lib/rds-database-auto-start-prevent-stack.js +4 -3
- package/lib/rds-database-auto-start-preventer.d.ts +19 -1
- package/lib/rds-database-auto-start-preventer.js +71 -80
- package/lib/settings/consts.d.ts +19 -0
- package/lib/settings/consts.js +23 -0
- package/package.json +8 -5
|
@@ -18,4 +18,5 @@ import { NoOpResult, StoppedResult } from './core/auto-start-prevent.predicates'
|
|
|
18
18
|
* @throws When the payload is invalid, the event is unsupported, a configured Slack secret is invalid, or stop did not reach `stopped`.
|
|
19
19
|
*/
|
|
20
20
|
export declare const processAutoStartPrevent: (input: unknown, context: DurableContext) => Promise<StoppedResult | NoOpResult>;
|
|
21
|
+
/** Lambda entry point: {@link processAutoStartPrevent} wrapped with the failure log and durable execution. */
|
|
21
22
|
export declare const handler: import("@aws/durable-execution-sdk-js").DurableLambdaHandler;
|
|
@@ -7,8 +7,68 @@ const web_api_1 = require("@slack/web-api");
|
|
|
7
7
|
const aws_lambda_secret_fetcher_1 = require("aws-lambda-secret-fetcher");
|
|
8
8
|
const strict_env_resolver_1 = require("strict-env-resolver");
|
|
9
9
|
const auto_start_prevent_predicates_1 = require("./core/auto-start-prevent.predicates");
|
|
10
|
+
const consts_1 = require("../settings/consts");
|
|
10
11
|
/** Shared RDS client for describe and stop API calls. */
|
|
11
12
|
const rdsClient = new client_rds_1.RDSClient({});
|
|
13
|
+
/**
|
|
14
|
+
* Per-request timeout for Slack API calls.
|
|
15
|
+
* The WebClient default is no timeout with ~30 minutes of retries, which exceeds the Lambda invocation timeout.
|
|
16
|
+
*/
|
|
17
|
+
const SLACK_REQUEST_TIMEOUT_MS = 30_000;
|
|
18
|
+
/** Slack retries after the first attempt, kept within the Lambda invocation timeout. */
|
|
19
|
+
const SLACK_RETRIES = 2;
|
|
20
|
+
/** Durable step names for StopDB*; kept per resource kind so existing execution histories still replay. */
|
|
21
|
+
const STOP_STEP_NAMES = {
|
|
22
|
+
instance: 'stop-db-instance',
|
|
23
|
+
cluster: 'stop-db-cluster',
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Describes the DB instance or cluster and returns its status, identifier, and tags.
|
|
27
|
+
* Falls back to `unknown`, the requested identifier, and no tags when the response has no resource.
|
|
28
|
+
*
|
|
29
|
+
* @param kind - Resource type to describe.
|
|
30
|
+
* @param identifier - DB instance or cluster identifier.
|
|
31
|
+
* @returns Wait state including the resource TagList.
|
|
32
|
+
*/
|
|
33
|
+
const describeResource = async (kind, identifier) => {
|
|
34
|
+
if (kind === 'instance') {
|
|
35
|
+
const res = await rdsClient.send(new client_rds_1.DescribeDBInstancesCommand({
|
|
36
|
+
DBInstanceIdentifier: identifier,
|
|
37
|
+
}));
|
|
38
|
+
const db = res.DBInstances?.[0];
|
|
39
|
+
return {
|
|
40
|
+
status: db?.DBInstanceStatus ?? auto_start_prevent_predicates_1.DB_STATUS.UNKNOWN,
|
|
41
|
+
identifier: db?.DBInstanceIdentifier ?? identifier,
|
|
42
|
+
tags: (db?.TagList ?? []),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const res = await rdsClient.send(new client_rds_1.DescribeDBClustersCommand({
|
|
46
|
+
DBClusterIdentifier: identifier,
|
|
47
|
+
}));
|
|
48
|
+
const cluster = res.DBClusters?.[0];
|
|
49
|
+
return {
|
|
50
|
+
status: cluster?.Status ?? auto_start_prevent_predicates_1.DB_STATUS.UNKNOWN,
|
|
51
|
+
identifier: cluster?.DBClusterIdentifier ?? identifier,
|
|
52
|
+
tags: (cluster?.TagList ?? []),
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Calls StopDBInstance or StopDBCluster.
|
|
57
|
+
*
|
|
58
|
+
* @param kind - Resource type to stop.
|
|
59
|
+
* @param identifier - DB instance or cluster identifier.
|
|
60
|
+
*/
|
|
61
|
+
const stopResource = async (kind, identifier) => {
|
|
62
|
+
if (kind === 'instance') {
|
|
63
|
+
await rdsClient.send(new client_rds_1.StopDBInstanceCommand({
|
|
64
|
+
DBInstanceIdentifier: identifier,
|
|
65
|
+
}));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
await rdsClient.send(new client_rds_1.StopDBClusterCommand({
|
|
69
|
+
DBClusterIdentifier: identifier,
|
|
70
|
+
}));
|
|
71
|
+
};
|
|
12
72
|
/**
|
|
13
73
|
* Durable Lambda handler for RDS auto-start prevention.
|
|
14
74
|
*
|
|
@@ -35,46 +95,21 @@ const processAutoStartPrevent = async (input, context) => {
|
|
|
35
95
|
});
|
|
36
96
|
// Requires AWS Parameters and Secrets Extension (ParamsAndSecrets layer) and
|
|
37
97
|
// AWS_SESSION_TOKEN from the Lambda runtime (aws-lambda-secret-fetcher ^0.6+).
|
|
98
|
+
// Fetched outside context.step: step results are persisted in the durable execution history,
|
|
99
|
+
// so the token and channel must not be returned from a step. Re-fetching on replay is read-only.
|
|
38
100
|
let slackSecret;
|
|
39
101
|
if (slackSecretName.length > 0) {
|
|
40
|
-
const slackSecretValue = await
|
|
41
|
-
return aws_lambda_secret_fetcher_1.secretFetcher.getSecretValue(slackSecretName);
|
|
42
|
-
});
|
|
102
|
+
const slackSecretValue = await aws_lambda_secret_fetcher_1.secretFetcher.getSecretValue(slackSecretName);
|
|
43
103
|
if (!(0, auto_start_prevent_predicates_1.isSlackSecret)(slackSecretValue)) {
|
|
44
104
|
throw new Error('Slack secret must be JSON with non-empty token and channel.');
|
|
45
105
|
}
|
|
46
106
|
slackSecret = slackSecretValue;
|
|
47
107
|
}
|
|
48
|
-
const
|
|
49
|
-
const isCluster = (0, auto_start_prevent_predicates_1.isDbClusterAutoStart)(detailType, detail);
|
|
50
|
-
if (!isInstance && !isCluster) {
|
|
51
|
-
throw new Error(`Unsupported event: detail-type=${detailType}, SourceType=${detail.SourceType}, EventID=${detail.EventID}`);
|
|
52
|
-
}
|
|
108
|
+
const kind = (0, auto_start_prevent_predicates_1.resolveResourceKind)(detailType, detail);
|
|
53
109
|
// Initial delay before the first describe (allows RDS to report a stable status).
|
|
54
|
-
await context.wait({ minutes: 1 });
|
|
110
|
+
await context.wait('initial-delay', { minutes: 1 });
|
|
55
111
|
// Wait until the resource is no longer in a transitional status; capture status and TagList.
|
|
56
|
-
const firstDescribe = await context.waitForCondition(async (_state, _ctx) => {
|
|
57
|
-
if (isInstance) {
|
|
58
|
-
const res = await rdsClient.send(new client_rds_1.DescribeDBInstancesCommand({
|
|
59
|
-
DBInstanceIdentifier: detail.SourceIdentifier,
|
|
60
|
-
}));
|
|
61
|
-
const db = res.DBInstances?.[0];
|
|
62
|
-
return {
|
|
63
|
-
status: db?.DBInstanceStatus ?? 'unknown',
|
|
64
|
-
identifier: db?.DBInstanceIdentifier ?? detail.SourceIdentifier,
|
|
65
|
-
tags: (db?.TagList ?? []),
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
const res = await rdsClient.send(new client_rds_1.DescribeDBClustersCommand({
|
|
69
|
-
DBClusterIdentifier: detail.SourceIdentifier,
|
|
70
|
-
}));
|
|
71
|
-
const cluster = res.DBClusters?.[0];
|
|
72
|
-
return {
|
|
73
|
-
status: cluster?.Status ?? 'unknown',
|
|
74
|
-
identifier: cluster?.DBClusterIdentifier ?? detail.SourceIdentifier,
|
|
75
|
-
tags: (cluster?.TagList ?? []),
|
|
76
|
-
};
|
|
77
|
-
}, {
|
|
112
|
+
const firstDescribe = await context.waitForCondition('wait-until-stable', async (_state, _ctx) => describeResource(kind, detail.SourceIdentifier), {
|
|
78
113
|
initialState: {
|
|
79
114
|
status: 'starting',
|
|
80
115
|
identifier: detail.SourceIdentifier,
|
|
@@ -85,73 +120,40 @@ const processAutoStartPrevent = async (input, context) => {
|
|
|
85
120
|
if (!(0, auto_start_prevent_predicates_1.matchTag)(params, firstDescribe.tags)) {
|
|
86
121
|
return (0, auto_start_prevent_predicates_1.tagMismatchNoOp)(firstDescribe.status);
|
|
87
122
|
}
|
|
88
|
-
let didStop = false;
|
|
89
|
-
let finalStatus = firstDescribe.status;
|
|
90
|
-
// When available, invoke StopDB* and wait until stopped.
|
|
91
|
-
const afterTagMatch = (0, auto_start_prevent_predicates_1.decideAfterTagMatch)(firstDescribe.status);
|
|
92
|
-
if (afterTagMatch.kind === 'stop') {
|
|
93
|
-
if (isInstance) {
|
|
94
|
-
await context.step('stop-db-instance', async () => {
|
|
95
|
-
await rdsClient.send(new client_rds_1.StopDBInstanceCommand({
|
|
96
|
-
DBInstanceIdentifier: detail.SourceIdentifier,
|
|
97
|
-
}));
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
await context.step('stop-db-cluster', async () => {
|
|
102
|
-
await rdsClient.send(new client_rds_1.StopDBClusterCommand({
|
|
103
|
-
DBClusterIdentifier: detail.SourceIdentifier,
|
|
104
|
-
}));
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
const stopped = await context.waitForCondition(async (_state, _ctx) => {
|
|
108
|
-
if (isInstance) {
|
|
109
|
-
const res = await rdsClient.send(new client_rds_1.DescribeDBInstancesCommand({
|
|
110
|
-
DBInstanceIdentifier: detail.SourceIdentifier,
|
|
111
|
-
}));
|
|
112
|
-
const db = res.DBInstances?.[0];
|
|
113
|
-
return {
|
|
114
|
-
status: db?.DBInstanceStatus ?? 'unknown',
|
|
115
|
-
identifier: db?.DBInstanceIdentifier ?? detail.SourceIdentifier,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
const res = await rdsClient.send(new client_rds_1.DescribeDBClustersCommand({
|
|
119
|
-
DBClusterIdentifier: detail.SourceIdentifier,
|
|
120
|
-
}));
|
|
121
|
-
const cluster = res.DBClusters?.[0];
|
|
122
|
-
return {
|
|
123
|
-
status: cluster?.Status ?? 'unknown',
|
|
124
|
-
identifier: cluster?.DBClusterIdentifier ?? detail.SourceIdentifier,
|
|
125
|
-
};
|
|
126
|
-
}, {
|
|
127
|
-
initialState: {
|
|
128
|
-
status: firstDescribe.status,
|
|
129
|
-
identifier: firstDescribe.identifier,
|
|
130
|
-
},
|
|
131
|
-
waitStrategy: auto_start_prevent_predicates_1.waitStrategyUntilStopped,
|
|
132
|
-
});
|
|
133
|
-
didStop = true;
|
|
134
|
-
finalStatus = stopped.status;
|
|
135
|
-
}
|
|
136
123
|
// Already stopped without calling StopDB* (e.g. stopped by another process) — no Slack notification.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
if (afterTagMatch.kind === 'error') {
|
|
142
|
-
throw new Error(afterTagMatch.message);
|
|
143
|
-
}
|
|
124
|
+
const afterTagMatch = (0, auto_start_prevent_predicates_1.decideAfterTagMatch)(firstDescribe);
|
|
125
|
+
if (afterTagMatch.kind === 'no-op') {
|
|
126
|
+
return afterTagMatch.result;
|
|
144
127
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
throw new Error(`DB status is not stopped after processing: ${finalStatus}`);
|
|
128
|
+
if (afterTagMatch.kind === 'error') {
|
|
129
|
+
throw new Error(afterTagMatch.message);
|
|
148
130
|
}
|
|
131
|
+
// Available: invoke StopDB* and wait until stopped.
|
|
132
|
+
await context.step(STOP_STEP_NAMES[kind], async () => {
|
|
133
|
+
await stopResource(kind, detail.SourceIdentifier);
|
|
134
|
+
});
|
|
135
|
+
// waitStrategyUntilStopped ends only on `stopped` and throws on any non-transitional status.
|
|
136
|
+
// Tags are dropped here so they are not persisted again on every check.
|
|
137
|
+
const stopped = await context.waitForCondition('wait-until-stopped', async (_state, _ctx) => {
|
|
138
|
+
const { status, identifier } = await describeResource(kind, detail.SourceIdentifier);
|
|
139
|
+
return { status, identifier };
|
|
140
|
+
}, {
|
|
141
|
+
initialState: {
|
|
142
|
+
status: firstDescribe.status,
|
|
143
|
+
identifier: firstDescribe.identifier,
|
|
144
|
+
},
|
|
145
|
+
waitStrategy: auto_start_prevent_predicates_1.waitStrategyUntilStopped,
|
|
146
|
+
});
|
|
149
147
|
const { region, account } = (0, auto_start_prevent_predicates_1.parseRdsSourceArn)(detail.SourceArn);
|
|
150
148
|
if (slackSecret !== undefined) {
|
|
151
149
|
const channel = slackSecret.channel;
|
|
152
|
-
const client = new web_api_1.WebClient(slackSecret.token
|
|
150
|
+
const client = new web_api_1.WebClient(slackSecret.token, {
|
|
151
|
+
timeout: SLACK_REQUEST_TIMEOUT_MS,
|
|
152
|
+
retryConfig: { retries: SLACK_RETRIES },
|
|
153
|
+
});
|
|
154
|
+
// Return nothing so the Slack API response is not persisted in the durable execution history.
|
|
153
155
|
await context.step('post-slack-messages', async () => {
|
|
154
|
-
|
|
156
|
+
await client.chat.postMessage((0, auto_start_prevent_predicates_1.buildSlackStopNotification)({
|
|
155
157
|
channel,
|
|
156
158
|
sourceType: detail.SourceType,
|
|
157
159
|
sourceIdentifier: detail.SourceIdentifier,
|
|
@@ -161,12 +163,48 @@ const processAutoStartPrevent = async (input, context) => {
|
|
|
161
163
|
});
|
|
162
164
|
}
|
|
163
165
|
return (0, auto_start_prevent_predicates_1.buildStoppedResult)({
|
|
164
|
-
finalStatus,
|
|
166
|
+
finalStatus: stopped.status,
|
|
165
167
|
account,
|
|
166
168
|
region,
|
|
167
169
|
identifier: detail.SourceIdentifier,
|
|
168
170
|
});
|
|
169
171
|
};
|
|
170
172
|
exports.processAutoStartPrevent = processAutoStartPrevent;
|
|
171
|
-
|
|
172
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0by1zdGFydC1wcmV2ZW50LmxhbWJkYS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mdW5jcy9hdXRvLXN0YXJ0LXByZXZlbnQubGFtYmRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDRFQUFxRjtBQUNyRixvREFNNkI7QUFDN0IsNENBQTJDO0FBQzNDLHlFQUEwRDtBQUMxRCw2REFBdUU7QUFDdkUsd0ZBa0I4QztBQUU5Qyx5REFBeUQ7QUFDekQsTUFBTSxTQUFTLEdBQUcsSUFBSSxzQkFBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBRXBDOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JHO0FBQ0ksTUFBTSx1QkFBdUIsR0FBRyxLQUFLLEVBQzFDLEtBQWMsRUFDZCxPQUF1QixFQUNjLEVBQUU7SUFDdkMsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxJQUFBLDhDQUFjLEVBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEQsTUFBTSxFQUFFLE1BQU0sRUFBRSxhQUFhLEVBQUUsVUFBVSxFQUFFLEdBQUcsS0FBSyxDQUFDO0lBRXBELE1BQU0sZUFBZSxHQUFHLHVDQUFpQixDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRSxtQ0FBYSxDQUFDLE1BQU0sRUFBRTtRQUMzRixJQUFJLEVBQUUsSUFBSTtRQUNWLE9BQU8sRUFBRSxFQUFFO0tBQ1osQ0FBQyxDQUFDO0lBQ0gsNkVBQTZFO0lBQzdFLCtFQUErRTtJQUMvRSxJQUFJLFdBQW9DLENBQUM7SUFDekMsSUFBSSxlQUFlLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQy9CLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLG9CQUFvQixFQUFFLEtBQUssSUFBSSxFQUFFO1lBQzNFLE9BQU8seUNBQWEsQ0FBQyxjQUFjLENBQWMsZUFBZSxDQUFDLENBQUM7UUFDcEUsQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsSUFB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SyxTQUFTLEVBQUUsQ0FBQztRQUM5QixNQUFNLE9BQU8sR0FBRyxXQUFXLENBQUMsT0FBTyxDQUFDO1FBQ3BDLE1BQU0sTUFBTSxHQUFHLElBQUksbUJBQVMsQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDaEQsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLHFCQUFxQixFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ25ELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQzVCLElBQUEsMERBQTBCLEVBQUM7Z0JBQ3pCLE9BQU87Z0JBQ1AsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO2dCQUM3QixnQkFBZ0IsRUFBRSxNQUFNLENBQUMsZ0JBQWdCO2dCQUN6QyxPQUFPO2dCQUNQLE1BQU07YUFDUCxDQUFDLENBQ0gsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELE9BQU8sSUFBQSxrREFBa0IsRUFBQztRQUN4QixXQUFXO1FBQ1gsT0FBTztRQUNQLE1BQU07UUFDTixVQUFVLEVBQUUsTUFBTSxDQUFDLGdCQUFnQjtLQUNwQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUM7QUFyTFcsUUFBQSx1QkFBdUIsMkJBcUxsQztBQUVXLFFBQUEsT0FBTyxHQUFHLElBQUEsK0NBQW9CLEVBQUMsK0JBQXVCLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHdpdGhEdXJhYmxlRXhlY3V0aW9uLCBEdXJhYmxlQ29udGV4dCB9IGZyb20gJ0Bhd3MvZHVyYWJsZS1leGVjdXRpb24tc2RrLWpzJztcbmltcG9ydCB7XG4gIFJEU0NsaWVudCxcbiAgRGVzY3JpYmVEQkluc3RhbmNlc0NvbW1hbmQsXG4gIERlc2NyaWJlREJDbHVzdGVyc0NvbW1hbmQsXG4gIFN0b3BEQkluc3RhbmNlQ29tbWFuZCxcbiAgU3RvcERCQ2x1c3RlckNvbW1hbmQsXG59IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1yZHMnO1xuaW1wb3J0IHsgV2ViQ2xpZW50IH0gZnJvbSAnQHNsYWNrL3dlYi1hcGknO1xuaW1wb3J0IHsgc2VjcmV0RmV0Y2hlciB9IGZyb20gJ2F3cy1sYW1iZGEtc2VjcmV0LWZldGNoZXInO1xuaW1wb3J0IHsgU3RyaWN0RW52UmVzb2x2ZXIsIFN0cmljdEVudlR5cGUgfSBmcm9tICdzdHJpY3QtZW52LXJlc29sdmVyJztcbmltcG9ydCB7XG4gIGJ1aWxkU2xhY2tTdG9wTm90aWZpY2F0aW9uLFxuICBidWlsZFN0b3BwZWRSZXN1bHQsXG4gIGRlY2lkZUFmdGVyVGFnTWF0Y2gsXG4gIGlzRGJDbHVzdGVyQXV0b1N0YXJ0LFxuICBpc0RiSW5zdGFuY2VBdXRvU3RhcnQsXG4gIGlzU2xhY2tTZWNyZXQsXG4gIG1hdGNoVGFnLFxuICBub3JtYWxpemVJbnB1dCxcbiAgTm9PcFJlc3VsdCxcbiAgcGFyc2VSZHNTb3VyY2VBcm4sXG4gIFdhaXRTdGF0ZSxcbiAgU2xhY2tTZWNyZXQsXG4gIFN0b3BwZWRSZXN1bHQsXG4gIFRhZyxcbiAgdGFnTWlzbWF0Y2hOb09wLFxuICB3YWl0U3RyYXRlZ3lVbnRpbFN0YWJsZSxcbiAgd2FpdFN0cmF0ZWd5VW50aWxTdG9wcGVkLFxufSBmcm9tICcuL2NvcmUvYXV0by1zdGFydC1wcmV2ZW50LnByZWRpY2F0ZXMnO1xuXG4vKiogU2hhcmVkIFJEUyBjbGllbnQgZm9yIGRlc2NyaWJlIGFuZCBzdG9wIEFQSSBjYWxscy4gKi9cbmNvbnN0IHJkc0NsaWVudCA9IG5ldyBSRFNDbGllbnQoe30pO1xuXG4vKipcbiAqIER1cmFibGUgTGFtYmRhIGhhbmRsZXIgZm9yIFJEUyBhdXRvLXN0YXJ0IHByZXZlbnRpb24uXG4gKlxuICogV29ya2Zsb3c6XG4gKiAxLiBXYWl0IDEgbWludXRlLCB0aGVuIHdhaXQgb24gRGVzY3JpYmVEQiogdW50aWwgdGhlIHJlc291cmNlIGxlYXZlcyB0cmFuc2l0aW9uYWwgc3RhdHVzZXMuXG4gKiAyLiBSZWFkIHRhZ3MgZnJvbSB0aGUgZGVzY3JpYmUgcmVzcG9uc2UgYFRhZ0xpc3RgOyBza2lwIHdoZW4ge0BsaW5rIG1hdGNoVGFnfSByZXR1cm5zIGZhbHNlLlxuICogMy4gSWYgc3RhdHVzIGlzIGBhdmFpbGFibGVgLCBjYWxsIFN0b3BEQiogYW5kIHdhaXQgdW50aWwgYHN0b3BwZWRgLlxuICogNC4gSWYgYWxyZWFkeSBgc3RvcHBlZGAgd2l0aG91dCBjYWxsaW5nIFN0b3BEQiosIHJldHVybiB7QGxpbmsgTm9PcFJlc3VsdH0gKG5vIFNsYWNrIG5vdGlmaWNhdGlvbikuXG4gKiA1LiBXaGVuIGBTTEFDS19TRUNSRVRfTkFNRWAgaXMgc2V0LCBwb3N0IHRvIFNsYWNrIG9ubHkgYWZ0ZXIgU3RvcERCKiB3YXMgaW52b2tlZCBhbmQgdGhlIHJlc291cmNlIHJlYWNoZWQgYHN0b3BwZWRgLiBXaGVuIGl0IGlzIHVuc2V0LCBza2lwIFNsYWNrLlxuICpcbiAqIFRhZyBtYXRjaGluZyB1c2VzIFJEUyBEZXNjcmliZSBBUElzIG9ubHk7IFJlc291cmNlIEdyb3VwcyBUYWdnaW5nIEFQSSBpcyBub3QgdXNlZC5cbiAqXG4gKiBAcGFyYW0gaW5wdXQgLSBgeyBldmVudCwgcGFyYW1zIH1gIGZyb20gRXZlbnRCcmlkZ2UgSW5wdXRUcmFuc2Zvcm1lciAoc2FtZSBzaGFwZSByZXF1aXJlZCBmb3IgZGlyZWN0IEludm9rZSkuXG4gKiBAcGFyYW0gY29udGV4dCAtIER1cmFibGUgZXhlY3V0aW9uIGNvbnRleHQgZm9yIHN0ZXBzIGFuZCB3YWl0cy5cbiAqIEByZXR1cm5zIHtAbGluayBTdG9wcGVkUmVzdWx0fSBvciB7QGxpbmsgTm9PcFJlc3VsdH0uXG4gKiBAdGhyb3dzIFdoZW4gdGhlIHBheWxvYWQgaXMgaW52YWxpZCwgdGhlIGV2ZW50IGlzIHVuc3VwcG9ydGVkLCBhIGNvbmZpZ3VyZWQgU2xhY2sgc2VjcmV0IGlzIGludmFsaWQsIG9yIHN0b3AgZGlkIG5vdCByZWFjaCBgc3RvcHBlZGAuXG4gKi9cbmV4cG9ydCBjb25zdCBwcm9jZXNzQXV0b1N0YXJ0UHJldmVudCA9IGFzeW5jIChcbiAgaW5wdXQ6IHVua25vd24sXG4gIGNvbnRleHQ6IER1cmFibGVDb250ZXh0LFxuKTogUHJvbWlzZTxTdG9wcGVkUmVzdWx0IHwgTm9PcFJlc3VsdD4gPT4ge1xuICBjb25zdCB7IGV2ZW50LCBwYXJhbXMgfSA9IG5vcm1hbGl6ZUlucHV0KGlucHV0KTtcbiAgY29uc3QgeyBkZXRhaWwsICdkZXRhaWwtdHlwZSc6IGRldGFpbFR5cGUgfSA9IGV2ZW50O1xuXG4gIGNvbnN0IHNsYWNrU2VjcmV0TmFtZSA9IFN0cmljdEVudlJlc29sdmVyLnJlc29sdmUoJ1NMQUNLX1NFQ1JFVF9OQU1FJywgU3RyaWN0RW52VHlwZS5TdHJpbmcsIHtcbiAgICB0cmltOiB0cnVlLFxuICAgIGRlZmF1bHQ6ICcnLFxuICB9KTtcbiAgLy8gUmVxdWlyZXMgQVdTIFBhcmFtZXRlcnMgYW5kIFNlY3JldHMgRXh0ZW5zaW9uIChQYXJhbXNBbmRTZWNyZXRzIGxheWVyKSBhbmRcbiAgLy8gQVdTX1NFU1NJT05fVE9LRU4gZnJvbSB0aGUgTGFtYmRhIHJ1bnRpbWUgKGF3cy1sYW1iZGEtc2VjcmV0LWZldGNoZXIgXjAuNispLlxuICBsZXQgc2xhY2tTZWNyZXQ6IFNsYWNrU2VjcmV0IHwgdW5kZWZpbmVkO1xuICBpZiAoc2xhY2tTZWNyZXROYW1lLmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCBzbGFja1NlY3JldFZhbHVlID0gYXdhaXQgY29udGV4dC5zdGVwKCdmZXRjaC1zbGFjay1zZWNyZXQnLCBhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4gc2VjcmV0RmV0Y2hlci5nZXRTZWNyZXRWYWx1ZTxTbGFja1NlY3JldD4oc2xhY2tTZWNyZXROYW1lKTtcbiAgICB9KTtcbiAgICBpZiAoIWlzU2xhY2tTZWNyZXQoc2xhY2tTZWNyZXRWYWx1ZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignU2xhY2sgc2VjcmV0IG11c3QgYmUgSlNPTiB3aXRoIG5vbi1lbXB0eSB0b2tlbiBhbmQgY2hhbm5lbC4nKTtcbiAgICB9XG4gICAgc2xhY2tTZWNyZXQgPSBzbGFja1NlY3JldFZhbHVlO1xuICB9XG5cbiAgY29uc3QgaXNJbnN0YW5jZSA9IGlzRGJJbnN0YW5jZUF1dG9TdGFydChkZXRhaWxUeXBlLCBkZXRhaWwpO1xuICBjb25zdCBpc0NsdXN0ZXIgPSBpc0RiQ2x1c3RlckF1dG9TdGFydChkZXRhaWxUeXBlLCBkZXRhaWwpO1xuXG4gIGlmICghaXNJbnN0YW5jZSAmJiAhaXNDbHVzdGVyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYFVuc3VwcG9ydGVkIGV2ZW50OiBkZXRhaWwtdHlwZT0ke2RldGFpbFR5cGV9LCBTb3VyY2VUeXBlPSR7ZGV0YWlsLlNvdXJjZVR5cGV9LCBFdmVudElEPSR7ZGV0YWlsLkV2ZW50SUR9YCxcbiAgICApO1xuICB9XG5cbiAgLy8gSW5pdGlhbCBkZWxheSBiZWZvcmUgdGhlIGZpcnN0IGRlc2NyaWJlIChhbGxvd3MgUkRTIHRvIHJlcG9ydCBhIHN0YWJsZSBzdGF0dXMpLlxuICBhd2FpdCBjb250ZXh0LndhaXQoeyBtaW51dGVzOiAxIH0pO1xuXG4gIC8vIFdhaXQgdW50aWwgdGhlIHJlc291cmNlIGlzIG5vIGxvbmdlciBpbiBhIHRyYW5zaXRpb25hbCBzdGF0dXM7IGNhcHR1cmUgc3RhdHVzIGFuZCBUYWdMaXN0LlxuICBjb25zdCBmaXJzdERlc2NyaWJlID0gYXdhaXQgY29udGV4dC53YWl0Rm9yQ29uZGl0aW9uPFdhaXRTdGF0ZT4oXG4gICAgYXN5bmMgKF9zdGF0ZSwgX2N0eCkgPT4ge1xuICAgICAgaWYgKGlzSW5zdGFuY2UpIHtcbiAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgcmRzQ2xpZW50LnNlbmQoXG4gICAgICAgICAgbmV3IERlc2NyaWJlREJJbnN0YW5jZXNDb21tYW5kKHtcbiAgICAgICAgICAgIERCSW5zdGFuY2VJZGVudGlmaWVyOiBkZXRhaWwuU291cmNlSWRlbnRpZmllcixcbiAgICAgICAgICB9KSxcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgZGIgPSByZXMuREJJbnN0YW5jZXM/LlswXTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzdGF0dXM6IGRiPy5EQkluc3RhbmNlU3RhdHVzID8/ICd1bmtub3duJyxcbiAgICAgICAgICBpZGVudGlmaWVyOiBkYj8uREJJbnN0YW5jZUlkZW50aWZpZXIgPz8gZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIsXG4gICAgICAgICAgdGFnczogKGRiPy5UYWdMaXN0ID8/IFtdKSBhcyBUYWdbXSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVzID0gYXdhaXQgcmRzQ2xpZW50LnNlbmQoXG4gICAgICAgIG5ldyBEZXNjcmliZURCQ2x1c3RlcnNDb21tYW5kKHtcbiAgICAgICAgICBEQkNsdXN0ZXJJZGVudGlmaWVyOiBkZXRhaWwuU291cmNlSWRlbnRpZmllcixcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgICAgY29uc3QgY2x1c3RlciA9IHJlcy5EQkNsdXN0ZXJzPy5bMF07XG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdGF0dXM6IGNsdXN0ZXI/LlN0YXR1cyA/PyAndW5rbm93bicsXG4gICAgICAgIGlkZW50aWZpZXI6IGNsdXN0ZXI/LkRCQ2x1c3RlcklkZW50aWZpZXIgPz8gZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIsXG4gICAgICAgIHRhZ3M6IChjbHVzdGVyPy5UYWdMaXN0ID8/IFtdKSBhcyBUYWdbXSxcbiAgICAgIH07XG4gICAgfSxcbiAgICB7XG4gICAgICBpbml0aWFsU3RhdGU6IHtcbiAgICAgICAgc3RhdHVzOiAnc3RhcnRpbmcnLFxuICAgICAgICBpZGVudGlmaWVyOiBkZXRhaWwuU291cmNlSWRlbnRpZmllcixcbiAgICAgIH0sXG4gICAgICB3YWl0U3RyYXRlZ3k6IHdhaXRTdHJhdGVneVVudGlsU3RhYmxlLFxuICAgIH0sXG4gICk7XG5cbiAgLy8gU2tpcCB3aGVuIFRhZ0xpc3QgaXMgbWlzc2luZyBvciBkb2VzIG5vdCBtYXRjaCB0YWdLZXkgLyB0YWdWYWx1ZXMuXG4gIGlmICghbWF0Y2hUYWcocGFyYW1zLCBmaXJzdERlc2NyaWJlLnRhZ3MpKSB7XG4gICAgcmV0dXJuIHRhZ01pc21hdGNoTm9PcChmaXJzdERlc2NyaWJlLnN0YXR1cyk7XG4gIH1cblxuICBsZXQgZGlkU3RvcCA9IGZhbHNlO1xuICBsZXQgZmluYWxTdGF0dXMgPSBmaXJzdERlc2NyaWJlLnN0YXR1cztcblxuICAvLyBXaGVuIGF2YWlsYWJsZSwgaW52b2tlIFN0b3BEQiogYW5kIHdhaXQgdW50aWwgc3RvcHBlZC5cbiAgY29uc3QgYWZ0ZXJUYWdNYXRjaCA9IGRlY2lkZUFmdGVyVGFnTWF0Y2goZmlyc3REZXNjcmliZS5zdGF0dXMpO1xuICBpZiAoYWZ0ZXJUYWdNYXRjaC5raW5kID09PSAnc3RvcCcpIHtcbiAgICBpZiAoaXNJbnN0YW5jZSkge1xuICAgICAgYXdhaXQgY29udGV4dC5zdGVwKCdzdG9wLWRiLWluc3RhbmNlJywgYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCByZHNDbGllbnQuc2VuZChcbiAgICAgICAgICBuZXcgU3RvcERCSW5zdGFuY2VDb21tYW5kKHtcbiAgICAgICAgICAgIERCSW5zdGFuY2VJZGVudGlmaWVyOiBkZXRhaWwuU291cmNlSWRlbnRpZmllcixcbiAgICAgICAgICB9KSxcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBhd2FpdCBjb250ZXh0LnN0ZXAoJ3N0b3AtZGItY2x1c3RlcicsIGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgcmRzQ2xpZW50LnNlbmQoXG4gICAgICAgICAgbmV3IFN0b3BEQkNsdXN0ZXJDb21tYW5kKHtcbiAgICAgICAgICAgIERCQ2x1c3RlcklkZW50aWZpZXI6IGRldGFpbC5Tb3VyY2VJZGVudGlmaWVyLFxuICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3Qgc3RvcHBlZCA9IGF3YWl0IGNvbnRleHQud2FpdEZvckNvbmRpdGlvbjxXYWl0U3RhdGU+KFxuICAgICAgYXN5bmMgKF9zdGF0ZSwgX2N0eCkgPT4ge1xuICAgICAgICBpZiAoaXNJbnN0YW5jZSkge1xuICAgICAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IHJkc0NsaWVudC5zZW5kKFxuICAgICAgICAgICAgbmV3IERlc2NyaWJlREJJbnN0YW5jZXNDb21tYW5kKHtcbiAgICAgICAgICAgICAgREJJbnN0YW5jZUlkZW50aWZpZXI6IGRldGFpbC5Tb3VyY2VJZGVudGlmaWVyLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBkYiA9IHJlcy5EQkluc3RhbmNlcz8uWzBdO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdGF0dXM6IGRiPy5EQkluc3RhbmNlU3RhdHVzID8/ICd1bmtub3duJyxcbiAgICAgICAgICAgIGlkZW50aWZpZXI6IGRiPy5EQkluc3RhbmNlSWRlbnRpZmllciA/PyBkZXRhaWwuU291cmNlSWRlbnRpZmllcixcbiAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgcmRzQ2xpZW50LnNlbmQoXG4gICAgICAgICAgbmV3IERlc2NyaWJlREJDbHVzdGVyc0NvbW1hbmQoe1xuICAgICAgICAgICAgREJDbHVzdGVySWRlbnRpZmllcjogZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIsXG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IGNsdXN0ZXIgPSByZXMuREJDbHVzdGVycz8uWzBdO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN0YXR1czogY2x1c3Rlcj8uU3RhdHVzID8/ICd1bmtub3duJyxcbiAgICAgICAgICBpZGVudGlmaWVyOiBjbHVzdGVyPy5EQkNsdXN0ZXJJZGVudGlmaWVyID8/IGRldGFpbC5Tb3VyY2VJZGVudGlmaWVyLFxuICAgICAgICB9O1xuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgaW5pdGlhbFN0YXRlOiB7XG4gICAgICAgICAgc3RhdHVzOiBmaXJzdERlc2NyaWJlLnN0YXR1cyxcbiAgICAgICAgICBpZGVudGlmaWVyOiBmaXJzdERlc2NyaWJlLmlkZW50aWZpZXIsXG4gICAgICAgIH0sXG4gICAgICAgIHdhaXRTdHJhdGVneTogd2FpdFN0cmF0ZWd5VW50aWxTdG9wcGVkLFxuICAgICAgfSxcbiAgICApO1xuXG4gICAgZGlkU3RvcCA9IHRydWU7XG4gICAgZmluYWxTdGF0dXMgPSBzdG9wcGVkLnN0YXR1cztcbiAgfVxuXG4gIC8vIEFscmVhZHkgc3RvcHBlZCB3aXRob3V0IGNhbGxpbmcgU3RvcERCKiAoZS5nLiBzdG9wcGVkIGJ5IGFub3RoZXIgcHJvY2Vzcykg4oCUIG5vIFNsYWNrIG5vdGlmaWNhdGlvbi5cbiAgaWYgKCFkaWRTdG9wKSB7XG4gICAgaWYgKGFmdGVyVGFnTWF0Y2gua2luZCA9PT0gJ25vLW9wJykge1xuICAgICAgcmV0dXJuIGFmdGVyVGFnTWF0Y2gucmVzdWx0O1xuICAgIH1cbiAgICBpZiAoYWZ0ZXJUYWdNYXRjaC5raW5kID09PSAnZXJyb3InKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYWZ0ZXJUYWdNYXRjaC5tZXNzYWdlKTtcbiAgICB9XG4gIH1cblxuICAvLyBGYWlsIHdoZW4gU3RvcERCKiB3YXMgY2FsbGVkIGJ1dCB0aGUgcmVzb3VyY2UgZGlkIG5vdCByZWFjaCBzdG9wcGVkLlxuICBpZiAoZmluYWxTdGF0dXMgIT09ICdzdG9wcGVkJykge1xuICAgIHRocm93IG5ldyBFcnJvcihgREIgc3RhdHVzIGlzIG5vdCBzdG9wcGVkIGFmdGVyIHByb2Nlc3Npbmc6ICR7ZmluYWxTdGF0dXN9YCk7XG4gIH1cblxuICBjb25zdCB7IHJlZ2lvbiwgYWNjb3VudCB9ID0gcGFyc2VSZHNTb3VyY2VBcm4oZGV0YWlsLlNvdXJjZUFybik7XG5cbiAgaWYgKHNsYWNrU2VjcmV0ICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBjaGFubmVsID0gc2xhY2tTZWNyZXQuY2hhbm5lbDtcbiAgICBjb25zdCBjbGllbnQgPSBuZXcgV2ViQ2xpZW50KHNsYWNrU2VjcmV0LnRva2VuKTtcbiAgICBhd2FpdCBjb250ZXh0LnN0ZXAoJ3Bvc3Qtc2xhY2stbWVzc2FnZXMnLCBhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4gY2xpZW50LmNoYXQucG9zdE1lc3NhZ2UoXG4gICAgICAgIGJ1aWxkU2xhY2tTdG9wTm90aWZpY2F0aW9uKHtcbiAgICAgICAgICBjaGFubmVsLFxuICAgICAgICAgIHNvdXJjZVR5cGU6IGRldGFpbC5Tb3VyY2VUeXBlLFxuICAgICAgICAgIHNvdXJjZUlkZW50aWZpZXI6IGRldGFpbC5Tb3VyY2VJZGVudGlmaWVyLFxuICAgICAgICAgIGFjY291bnQsXG4gICAgICAgICAgcmVnaW9uLFxuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gYnVpbGRTdG9wcGVkUmVzdWx0KHtcbiAgICBmaW5hbFN0YXR1cyxcbiAgICBhY2NvdW50LFxuICAgIHJlZ2lvbixcbiAgICBpZGVudGlmaWVyOiBkZXRhaWwuU291cmNlSWRlbnRpZmllcixcbiAgfSk7XG59O1xuXG5leHBvcnQgY29uc3QgaGFuZGxlciA9IHdpdGhEdXJhYmxlRXhlY3V0aW9uKHByb2Nlc3NBdXRvU3RhcnRQcmV2ZW50KTtcbiJdfQ==
|
|
173
|
+
/**
|
|
174
|
+
* Returns the RDS source identifier from the input, or undefined when the input is invalid.
|
|
175
|
+
*
|
|
176
|
+
* @param input - Raw handler input.
|
|
177
|
+
* @returns DB instance or cluster identifier when available.
|
|
178
|
+
*/
|
|
179
|
+
const sourceIdentifierOf = (input) => {
|
|
180
|
+
try {
|
|
181
|
+
return (0, auto_start_prevent_predicates_1.normalizeInput)(input).event.detail.SourceIdentifier;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Runs {@link processAutoStartPrevent} and logs {@link AUTO_START_PREVENT_FAILED_LOG_TERM} before rethrowing,
|
|
189
|
+
* because a failed durable execution does not raise the Lambda `Errors` metric.
|
|
190
|
+
*
|
|
191
|
+
* @param input - `{ event, params }` from EventBridge InputTransformer.
|
|
192
|
+
* @param context - Durable execution context for steps and waits.
|
|
193
|
+
* @returns {@link StoppedResult} or {@link NoOpResult}.
|
|
194
|
+
* @throws The error from {@link processAutoStartPrevent}.
|
|
195
|
+
*/
|
|
196
|
+
const processAutoStartPreventWithFailureLog = async (input, context) => {
|
|
197
|
+
try {
|
|
198
|
+
return await (0, exports.processAutoStartPrevent)(input, context);
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
console.error(consts_1.AUTO_START_PREVENT_FAILED_LOG_TERM, {
|
|
202
|
+
identifier: sourceIdentifierOf(input),
|
|
203
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
204
|
+
});
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
/** Lambda entry point: {@link processAutoStartPrevent} wrapped with the failure log and durable execution. */
|
|
209
|
+
exports.handler = (0, durable_execution_sdk_js_1.withDurableExecution)(processAutoStartPreventWithFailureLog);
|
|
210
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0by1zdGFydC1wcmV2ZW50LmxhbWJkYS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mdW5jcy9hdXRvLXN0YXJ0LXByZXZlbnQubGFtYmRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDRFQUFxRjtBQUNyRixvREFNNkI7QUFDN0IsNENBQTJDO0FBQzNDLHlFQUEwRDtBQUMxRCw2REFBdUU7QUFDdkUsd0ZBbUI4QztBQUM5QywrQ0FBd0U7QUFFeEUseURBQXlEO0FBQ3pELE1BQU0sU0FBUyxHQUFHLElBQUksc0JBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUVwQzs7O0dBR0c7QUFDSCxNQUFNLHdCQUF3QixHQUFHLE1BQU0sQ0FBQztBQUV4Qyx3RkFBd0Y7QUFDeEYsTUFBTSxhQUFhLEdBQUcsQ0FBQyxDQUFDO0FBRXhCLDJHQUEyRztBQUMzRyxNQUFNLGVBQWUsR0FBaUM7SUFDcEQsUUFBUSxFQUFFLGtCQUFrQjtJQUM1QixPQUFPLEVBQUUsaUJBQWlCO0NBQzNCLENBQUM7QUFFRjs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxnQkFBZ0IsR0FBRyxLQUFLLEVBQUUsSUFBa0IsRUFBRSxVQUFrQixFQUFnQyxFQUFFO0lBQ3RHLElBQUksSUFBSSxLQUFLLFVBQVUsRUFBRSxDQUFDO1FBQ3hCLE1BQU0sR0FBRyxHQUFHLE1BQU0sU0FBUyxDQUFDLElBQUksQ0FDOUIsSUFBSSx1Q0FBMEIsQ0FBQztZQUM3QixvQkFBb0IsRUFBRSxVQUFVO1NBQ2pDLENBQUMsQ0FDSCxDQUFDO1FBQ0YsTUFBTSxFQUFFLEdBQUcsR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2hDLE9BQU87WUFDTCxNQUFNLEVBQUUsRUFBRSxFQUFFLGdCQUFnQixJQUFJLHlDQUFTLENBQUMsT0FBTztZQUNqRCxVQUFVLEVBQUUsRUFBRSxFQUFFLG9CQUFvQixJQUFJLFVBQVU7WUFDbEQsSUFBSSxFQUFFLENBQUMsRUFB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aEUsSUFBSSxDQUFDO1FBQ0gsT0FBTyxJQUFBLDhDQUFjLEVBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztJQUM3RCxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztBQUNILENBQUMsQ0FBQztBQUVGOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxxQ0FBcUMsR0FBRyxLQUFLLEVBQ2pELEtBQWMsRUFDZCxPQUF1QixFQUNjLEVBQUU7SUFDdkMsSUFBSSxDQUFDO1FBQ0gsT0FBTyxNQUFNLElBQUEsK0JBQXVCLEVBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ3ZELENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsT0FBTyxDQUFDLEtBQUssQ0FBQywyQ0FBa0MsRUFBRTtZQUNoRCxVQUFVLEVBQUUsa0JBQWtCLENBQUMsS0FBSyxDQUFDO1lBQ3JDLFlBQVksRUFBRSxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDO1NBQ3JFLENBQUMsQ0FBQztRQUNILE1BQU0sS0FBSyxDQUFDO0lBQ2QsQ0FBQztBQUNILENBQUMsQ0FBQztBQUVGLDhHQUE4RztBQUNqRyxRQUFBLE9BQU8sR0FBRyxJQUFBLCtDQUFvQixFQUFDLHFDQUFxQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyB3aXRoRHVyYWJsZUV4ZWN1dGlvbiwgRHVyYWJsZUNvbnRleHQgfSBmcm9tICdAYXdzL2R1cmFibGUtZXhlY3V0aW9uLXNkay1qcyc7XG5pbXBvcnQge1xuICBSRFNDbGllbnQsXG4gIERlc2NyaWJlREJJbnN0YW5jZXNDb21tYW5kLFxuICBEZXNjcmliZURCQ2x1c3RlcnNDb21tYW5kLFxuICBTdG9wREJJbnN0YW5jZUNvbW1hbmQsXG4gIFN0b3BEQkNsdXN0ZXJDb21tYW5kLFxufSBmcm9tICdAYXdzLXNkay9jbGllbnQtcmRzJztcbmltcG9ydCB7IFdlYkNsaWVudCB9IGZyb20gJ0BzbGFjay93ZWItYXBpJztcbmltcG9ydCB7IHNlY3JldEZldGNoZXIgfSBmcm9tICdhd3MtbGFtYmRhLXNlY3JldC1mZXRjaGVyJztcbmltcG9ydCB7IFN0cmljdEVudlJlc29sdmVyLCBTdHJpY3RFbnZUeXBlIH0gZnJvbSAnc3RyaWN0LWVudi1yZXNvbHZlcic7XG5pbXBvcnQge1xuICBidWlsZFNsYWNrU3RvcE5vdGlmaWNhdGlvbixcbiAgYnVpbGRTdG9wcGVkUmVzdWx0LFxuICBEQl9TVEFUVVMsXG4gIGRlY2lkZUFmdGVyVGFnTWF0Y2gsXG4gIGlzU2xhY2tTZWNyZXQsXG4gIG1hdGNoVGFnLFxuICBub3JtYWxpemVJbnB1dCxcbiAgTm9PcFJlc3VsdCxcbiAgcGFyc2VSZHNTb3VyY2VBcm4sXG4gIFJlc291cmNlS2luZCxcbiAgcmVzb2x2ZVJlc291cmNlS2luZCxcbiAgV2FpdFN0YXRlLFxuICBTbGFja1NlY3JldCxcbiAgU3RvcHBlZFJlc3VsdCxcbiAgVGFnLFxuICB0YWdNaXNtYXRjaE5vT3AsXG4gIHdhaXRTdHJhdGVneVVudGlsU3RhYmxlLFxuICB3YWl0U3RyYXRlZ3lVbnRpbFN0b3BwZWQsXG59IGZyb20gJy4vY29yZS9hdXRvLXN0YXJ0LXByZXZlbnQucHJlZGljYXRlcyc7XG5pbXBvcnQgeyBBVVRPX1NUQVJUX1BSRVZFTlRfRkFJTEVEX0xPR19URVJNIH0gZnJvbSAnLi4vc2V0dGluZ3MvY29uc3RzJztcblxuLyoqIFNoYXJlZCBSRFMgY2xpZW50IGZvciBkZXNjcmliZSBhbmQgc3RvcCBBUEkgY2FsbHMuICovXG5jb25zdCByZHNDbGllbnQgPSBuZXcgUkRTQ2xpZW50KHt9KTtcblxuLyoqXG4gKiBQZXItcmVxdWVzdCB0aW1lb3V0IGZvciBTbGFjayBBUEkgY2FsbHMuXG4gKiBUaGUgV2ViQ2xpZW50IGRlZmF1bHQgaXMgbm8gdGltZW91dCB3aXRoIH4zMCBtaW51dGVzIG9mIHJldHJpZXMsIHdoaWNoIGV4Y2VlZHMgdGhlIExhbWJkYSBpbnZvY2F0aW9uIHRpbWVvdXQuXG4gKi9cbmNvbnN0IFNMQUNLX1JFUVVFU1RfVElNRU9VVF9NUyA9IDMwXzAwMDtcblxuLyoqIFNsYWNrIHJldHJpZXMgYWZ0ZXIgdGhlIGZpcnN0IGF0dGVtcHQsIGtlcHQgd2l0aGluIHRoZSBMYW1iZGEgaW52b2NhdGlvbiB0aW1lb3V0LiAqL1xuY29uc3QgU0xBQ0tfUkVUUklFUyA9IDI7XG5cbi8qKiBEdXJhYmxlIHN0ZXAgbmFtZXMgZm9yIFN0b3BEQio7IGtlcHQgcGVyIHJlc291cmNlIGtpbmQgc28gZXhpc3RpbmcgZXhlY3V0aW9uIGhpc3RvcmllcyBzdGlsbCByZXBsYXkuICovXG5jb25zdCBTVE9QX1NURVBfTkFNRVM6IFJlY29yZDxSZXNvdXJjZUtpbmQsIHN0cmluZz4gPSB7XG4gIGluc3RhbmNlOiAnc3RvcC1kYi1pbnN0YW5jZScsXG4gIGNsdXN0ZXI6ICdzdG9wLWRiLWNsdXN0ZXInLFxufTtcblxuLyoqXG4gKiBEZXNjcmliZXMgdGhlIERCIGluc3RhbmNlIG9yIGNsdXN0ZXIgYW5kIHJldHVybnMgaXRzIHN0YXR1cywgaWRlbnRpZmllciwgYW5kIHRhZ3MuXG4gKiBGYWxscyBiYWNrIHRvIGB1bmtub3duYCwgdGhlIHJlcXVlc3RlZCBpZGVudGlmaWVyLCBhbmQgbm8gdGFncyB3aGVuIHRoZSByZXNwb25zZSBoYXMgbm8gcmVzb3VyY2UuXG4gKlxuICogQHBhcmFtIGtpbmQgLSBSZXNvdXJjZSB0eXBlIHRvIGRlc2NyaWJlLlxuICogQHBhcmFtIGlkZW50aWZpZXIgLSBEQiBpbnN0YW5jZSBvciBjbHVzdGVyIGlkZW50aWZpZXIuXG4gKiBAcmV0dXJucyBXYWl0IHN0YXRlIGluY2x1ZGluZyB0aGUgcmVzb3VyY2UgVGFnTGlzdC5cbiAqL1xuY29uc3QgZGVzY3JpYmVSZXNvdXJjZSA9IGFzeW5jIChraW5kOiBSZXNvdXJjZUtpbmQsIGlkZW50aWZpZXI6IHN0cmluZyk6IFByb21pc2U8UmVxdWlyZWQ8V2FpdFN0YXRlPj4gPT4ge1xuICBpZiAoa2luZCA9PT0gJ2luc3RhbmNlJykge1xuICAgIGNvbnN0IHJlcyA9IGF3YWl0IHJkc0NsaWVudC5zZW5kKFxuICAgICAgbmV3IERlc2NyaWJlREJJbnN0YW5jZXNDb21tYW5kKHtcbiAgICAgICAgREJJbnN0YW5jZUlkZW50aWZpZXI6IGlkZW50aWZpZXIsXG4gICAgICB9KSxcbiAgICApO1xuICAgIGNvbnN0IGRiID0gcmVzLkRCSW5zdGFuY2VzPy5bMF07XG4gICAgcmV0dXJuIHtcbiAgICAgIHN0YXR1czogZGI/LkRCSW5zdGFuY2VTdGF0dXMgPz8gREJfU1RBVFVTLlVOS05PV04sXG4gICAgICBpZGVudGlmaWVyOiBkYj8uREJJbnN0YW5jZUlkZW50aWZpZXIgPz8gaWRlbnRpZmllcixcbiAgICAgIHRhZ3M6IChkYj8uVGFnTGlzdCA/PyBbXSkgYXMgVGFnW10sXG4gICAgfTtcbiAgfVxuXG4gIGNvbnN0IHJlcyA9IGF3YWl0IHJkc0NsaWVudC5zZW5kKFxuICAgIG5ldyBEZXNjcmliZURCQ2x1c3RlcnNDb21tYW5kKHtcbiAgICAgIERCQ2x1c3RlcklkZW50aWZpZXI6IGlkZW50aWZpZXIsXG4gICAgfSksXG4gICk7XG4gIGNvbnN0IGNsdXN0ZXIgPSByZXMuREJDbHVzdGVycz8uWzBdO1xuICByZXR1cm4ge1xuICAgIHN0YXR1czogY2x1c3Rlcj8uU3RhdHVzID8/IERCX1NUQVRVUy5VTktOT1dOLFxuICAgIGlkZW50aWZpZXI6IGNsdXN0ZXI/LkRCQ2x1c3RlcklkZW50aWZpZXIgPz8gaWRlbnRpZmllcixcbiAgICB0YWdzOiAoY2x1c3Rlcj8uVGFnTGlzdCA/PyBbXSkgYXMgVGFnW10sXG4gIH07XG59O1xuXG4vKipcbiAqIENhbGxzIFN0b3BEQkluc3RhbmNlIG9yIFN0b3BEQkNsdXN0ZXIuXG4gKlxuICogQHBhcmFtIGtpbmQgLSBSZXNvdXJjZSB0eXBlIHRvIHN0b3AuXG4gKiBAcGFyYW0gaWRlbnRpZmllciAtIERCIGluc3RhbmNlIG9yIGNsdXN0ZXIgaWRlbnRpZmllci5cbiAqL1xuY29uc3Qgc3RvcFJlc291cmNlID0gYXN5bmMgKGtpbmQ6IFJlc291cmNlS2luZCwgaWRlbnRpZmllcjogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gIGlmIChraW5kID09PSAnaW5zdGFuY2UnKSB7XG4gICAgYXdhaXQgcmRzQ2xpZW50LnNlbmQoXG4gICAgICBuZXcgU3RvcERCSW5zdGFuY2VDb21tYW5kKHtcbiAgICAgICAgREJJbnN0YW5jZUlkZW50aWZpZXI6IGlkZW50aWZpZXIsXG4gICAgICB9KSxcbiAgICApO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGF3YWl0IHJkc0NsaWVudC5zZW5kKFxuICAgIG5ldyBTdG9wREJDbHVzdGVyQ29tbWFuZCh7XG4gICAgICBEQkNsdXN0ZXJJZGVudGlmaWVyOiBpZGVudGlmaWVyLFxuICAgIH0pLFxuICApO1xufTtcblxuLyoqXG4gKiBEdXJhYmxlIExhbWJkYSBoYW5kbGVyIGZvciBSRFMgYXV0by1zdGFydCBwcmV2ZW50aW9uLlxuICpcbiAqIFdvcmtmbG93OlxuICogMS4gV2FpdCAxIG1pbnV0ZSwgdGhlbiB3YWl0IG9uIERlc2NyaWJlREIqIHVudGlsIHRoZSByZXNvdXJjZSBsZWF2ZXMgdHJhbnNpdGlvbmFsIHN0YXR1c2VzLlxuICogMi4gUmVhZCB0YWdzIGZyb20gdGhlIGRlc2NyaWJlIHJlc3BvbnNlIGBUYWdMaXN0YDsgc2tpcCB3aGVuIHtAbGluayBtYXRjaFRhZ30gcmV0dXJucyBmYWxzZS5cbiAqIDMuIElmIHN0YXR1cyBpcyBgYXZhaWxhYmxlYCwgY2FsbCBTdG9wREIqIGFuZCB3YWl0IHVudGlsIGBzdG9wcGVkYC5cbiAqIDQuIElmIGFscmVhZHkgYHN0b3BwZWRgIHdpdGhvdXQgY2FsbGluZyBTdG9wREIqLCByZXR1cm4ge0BsaW5rIE5vT3BSZXN1bHR9IChubyBTbGFjayBub3RpZmljYXRpb24pLlxuICogNS4gV2hlbiBgU0xBQ0tfU0VDUkVUX05BTUVgIGlzIHNldCwgcG9zdCB0byBTbGFjayBvbmx5IGFmdGVyIFN0b3BEQiogd2FzIGludm9rZWQgYW5kIHRoZSByZXNvdXJjZSByZWFjaGVkIGBzdG9wcGVkYC4gV2hlbiBpdCBpcyB1bnNldCwgc2tpcCBTbGFjay5cbiAqXG4gKiBUYWcgbWF0Y2hpbmcgdXNlcyBSRFMgRGVzY3JpYmUgQVBJcyBvbmx5OyBSZXNvdXJjZSBHcm91cHMgVGFnZ2luZyBBUEkgaXMgbm90IHVzZWQuXG4gKlxuICogQHBhcmFtIGlucHV0IC0gYHsgZXZlbnQsIHBhcmFtcyB9YCBmcm9tIEV2ZW50QnJpZGdlIElucHV0VHJhbnNmb3JtZXIgKHNhbWUgc2hhcGUgcmVxdWlyZWQgZm9yIGRpcmVjdCBJbnZva2UpLlxuICogQHBhcmFtIGNvbnRleHQgLSBEdXJhYmxlIGV4ZWN1dGlvbiBjb250ZXh0IGZvciBzdGVwcyBhbmQgd2FpdHMuXG4gKiBAcmV0dXJucyB7QGxpbmsgU3RvcHBlZFJlc3VsdH0gb3Ige0BsaW5rIE5vT3BSZXN1bHR9LlxuICogQHRocm93cyBXaGVuIHRoZSBwYXlsb2FkIGlzIGludmFsaWQsIHRoZSBldmVudCBpcyB1bnN1cHBvcnRlZCwgYSBjb25maWd1cmVkIFNsYWNrIHNlY3JldCBpcyBpbnZhbGlkLCBvciBzdG9wIGRpZCBub3QgcmVhY2ggYHN0b3BwZWRgLlxuICovXG5leHBvcnQgY29uc3QgcHJvY2Vzc0F1dG9TdGFydFByZXZlbnQgPSBhc3luYyAoXG4gIGlucHV0OiB1bmtub3duLFxuICBjb250ZXh0OiBEdXJhYmxlQ29udGV4dCxcbik6IFByb21pc2U8U3RvcHBlZFJlc3VsdCB8IE5vT3BSZXN1bHQ+ID0+IHtcbiAgY29uc3QgeyBldmVudCwgcGFyYW1zIH0gPSBub3JtYWxpemVJbnB1dChpbnB1dCk7XG4gIGNvbnN0IHsgZGV0YWlsLCAnZGV0YWlsLXR5cGUnOiBkZXRhaWxUeXBlIH0gPSBldmVudDtcblxuICBjb25zdCBzbGFja1NlY3JldE5hbWUgPSBTdHJpY3RFbnZSZXNvbHZlci5yZXNvbHZlKCdTTEFDS19TRUNSRVRfTkFNRScsIFN0cmljdEVudlR5cGUuU3RyaW5nLCB7XG4gICAgdHJpbTogdHJ1ZSxcbiAgICBkZWZhdWx0OiAnJyxcbiAgfSk7XG4gIC8vIFJlcXVpcmVzIEFXUyBQYXJhbWV0ZXJzIGFuZCBTZWNyZXRzIEV4dGVuc2lvbiAoUGFyYW1zQW5kU2VjcmV0cyBsYXllcikgYW5kXG4gIC8vIEFXU19TRVNTSU9OX1RPS0VOIGZyb20gdGhlIExhbWJkYSBydW50aW1lIChhd3MtbGFtYmRhLXNlY3JldC1mZXRjaGVyIF4wLjYrKS5cbiAgLy8gRmV0Y2hlZCBvdXRzaWRlIGNvbnRleHQuc3RlcDogc3RlcCByZXN1bHRzIGFyZSBwZXJzaXN0ZWQgaW4gdGhlIGR1cmFibGUgZXhlY3V0aW9uIGhpc3RvcnksXG4gIC8vIHNvIHRoZSB0b2tlbiBhbmQgY2hhbm5lbCBtdXN0IG5vdCBiZSByZXR1cm5lZCBmcm9tIGEgc3RlcC4gUmUtZmV0Y2hpbmcgb24gcmVwbGF5IGlzIHJlYWQtb25seS5cbiAgbGV0IHNsYWNrU2VjcmV0OiBTbGFja1NlY3JldCB8IHVuZGVmaW5lZDtcbiAgaWYgKHNsYWNrU2VjcmV0TmFtZS5sZW5ndGggPiAwKSB7XG4gICAgY29uc3Qgc2xhY2tTZWNyZXRWYWx1ZSA9IGF3YWl0IHNlY3JldEZldGNoZXIuZ2V0U2VjcmV0VmFsdWU8U2xhY2tTZWNyZXQ+KHNsYWNrU2VjcmV0TmFtZSk7XG4gICAgaWYgKCFpc1NsYWNrU2VjcmV0KHNsYWNrU2VjcmV0VmFsdWUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NsYWNrIHNlY3JldCBtdXN0IGJlIEpTT04gd2l0aCBub24tZW1wdHkgdG9rZW4gYW5kIGNoYW5uZWwuJyk7XG4gICAgfVxuICAgIHNsYWNrU2VjcmV0ID0gc2xhY2tTZWNyZXRWYWx1ZTtcbiAgfVxuXG4gIGNvbnN0IGtpbmQgPSByZXNvbHZlUmVzb3VyY2VLaW5kKGRldGFpbFR5cGUsIGRldGFpbCk7XG5cbiAgLy8gSW5pdGlhbCBkZWxheSBiZWZvcmUgdGhlIGZpcnN0IGRlc2NyaWJlIChhbGxvd3MgUkRTIHRvIHJlcG9ydCBhIHN0YWJsZSBzdGF0dXMpLlxuICBhd2FpdCBjb250ZXh0LndhaXQoJ2luaXRpYWwtZGVsYXknLCB7IG1pbnV0ZXM6IDEgfSk7XG5cbiAgLy8gV2FpdCB1bnRpbCB0aGUgcmVzb3VyY2UgaXMgbm8gbG9uZ2VyIGluIGEgdHJhbnNpdGlvbmFsIHN0YXR1czsgY2FwdHVyZSBzdGF0dXMgYW5kIFRhZ0xpc3QuXG4gIGNvbnN0IGZpcnN0RGVzY3JpYmUgPSBhd2FpdCBjb250ZXh0LndhaXRGb3JDb25kaXRpb248V2FpdFN0YXRlPihcbiAgICAnd2FpdC11bnRpbC1zdGFibGUnLFxuICAgIGFzeW5jIChfc3RhdGUsIF9jdHgpID0+IGRlc2NyaWJlUmVzb3VyY2Uoa2luZCwgZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIpLFxuICAgIHtcbiAgICAgIGluaXRpYWxTdGF0ZToge1xuICAgICAgICBzdGF0dXM6ICdzdGFydGluZycsXG4gICAgICAgIGlkZW50aWZpZXI6IGRldGFpbC5Tb3VyY2VJZGVudGlmaWVyLFxuICAgICAgfSxcbiAgICAgIHdhaXRTdHJhdGVneTogd2FpdFN0cmF0ZWd5VW50aWxTdGFibGUsXG4gICAgfSxcbiAgKTtcblxuICAvLyBTa2lwIHdoZW4gVGFnTGlzdCBpcyBtaXNzaW5nIG9yIGRvZXMgbm90IG1hdGNoIHRhZ0tleSAvIHRhZ1ZhbHVlcy5cbiAgaWYgKCFtYXRjaFRhZyhwYXJhbXMsIGZpcnN0RGVzY3JpYmUudGFncykpIHtcbiAgICByZXR1cm4gdGFnTWlzbWF0Y2hOb09wKGZpcnN0RGVzY3JpYmUuc3RhdHVzKTtcbiAgfVxuXG4gIC8vIEFscmVhZHkgc3RvcHBlZCB3aXRob3V0IGNhbGxpbmcgU3RvcERCKiAoZS5nLiBzdG9wcGVkIGJ5IGFub3RoZXIgcHJvY2Vzcykg4oCUIG5vIFNsYWNrIG5vdGlmaWNhdGlvbi5cbiAgY29uc3QgYWZ0ZXJUYWdNYXRjaCA9IGRlY2lkZUFmdGVyVGFnTWF0Y2goZmlyc3REZXNjcmliZSk7XG4gIGlmIChhZnRlclRhZ01hdGNoLmtpbmQgPT09ICduby1vcCcpIHtcbiAgICByZXR1cm4gYWZ0ZXJUYWdNYXRjaC5yZXN1bHQ7XG4gIH1cbiAgaWYgKGFmdGVyVGFnTWF0Y2gua2luZCA9PT0gJ2Vycm9yJykge1xuICAgIHRocm93IG5ldyBFcnJvcihhZnRlclRhZ01hdGNoLm1lc3NhZ2UpO1xuICB9XG5cbiAgLy8gQXZhaWxhYmxlOiBpbnZva2UgU3RvcERCKiBhbmQgd2FpdCB1bnRpbCBzdG9wcGVkLlxuICBhd2FpdCBjb250ZXh0LnN0ZXAoU1RPUF9TVEVQX05BTUVTW2tpbmRdLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgc3RvcFJlc291cmNlKGtpbmQsIGRldGFpbC5Tb3VyY2VJZGVudGlmaWVyKTtcbiAgfSk7XG5cbiAgLy8gd2FpdFN0cmF0ZWd5VW50aWxTdG9wcGVkIGVuZHMgb25seSBvbiBgc3RvcHBlZGAgYW5kIHRocm93cyBvbiBhbnkgbm9uLXRyYW5zaXRpb25hbCBzdGF0dXMuXG4gIC8vIFRhZ3MgYXJlIGRyb3BwZWQgaGVyZSBzbyB0aGV5IGFyZSBub3QgcGVyc2lzdGVkIGFnYWluIG9uIGV2ZXJ5IGNoZWNrLlxuICBjb25zdCBzdG9wcGVkID0gYXdhaXQgY29udGV4dC53YWl0Rm9yQ29uZGl0aW9uPFdhaXRTdGF0ZT4oXG4gICAgJ3dhaXQtdW50aWwtc3RvcHBlZCcsXG4gICAgYXN5bmMgKF9zdGF0ZSwgX2N0eCkgPT4ge1xuICAgICAgY29uc3QgeyBzdGF0dXMsIGlkZW50aWZpZXIgfSA9IGF3YWl0IGRlc2NyaWJlUmVzb3VyY2Uoa2luZCwgZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIpO1xuICAgICAgcmV0dXJuIHsgc3RhdHVzLCBpZGVudGlmaWVyIH07XG4gICAgfSxcbiAgICB7XG4gICAgICBpbml0aWFsU3RhdGU6IHtcbiAgICAgICAgc3RhdHVzOiBmaXJzdERlc2NyaWJlLnN0YXR1cyxcbiAgICAgICAgaWRlbnRpZmllcjogZmlyc3REZXNjcmliZS5pZGVudGlmaWVyLFxuICAgICAgfSxcbiAgICAgIHdhaXRTdHJhdGVneTogd2FpdFN0cmF0ZWd5VW50aWxTdG9wcGVkLFxuICAgIH0sXG4gICk7XG5cbiAgY29uc3QgeyByZWdpb24sIGFjY291bnQgfSA9IHBhcnNlUmRzU291cmNlQXJuKGRldGFpbC5Tb3VyY2VBcm4pO1xuXG4gIGlmIChzbGFja1NlY3JldCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgY2hhbm5lbCA9IHNsYWNrU2VjcmV0LmNoYW5uZWw7XG4gICAgY29uc3QgY2xpZW50ID0gbmV3IFdlYkNsaWVudChzbGFja1NlY3JldC50b2tlbiwge1xuICAgICAgdGltZW91dDogU0xBQ0tfUkVRVUVTVF9USU1FT1VUX01TLFxuICAgICAgcmV0cnlDb25maWc6IHsgcmV0cmllczogU0xBQ0tfUkVUUklFUyB9LFxuICAgIH0pO1xuICAgIC8vIFJldHVybiBub3RoaW5nIHNvIHRoZSBTbGFjayBBUEkgcmVzcG9uc2UgaXMgbm90IHBlcnNpc3RlZCBpbiB0aGUgZHVyYWJsZSBleGVjdXRpb24gaGlzdG9yeS5cbiAgICBhd2FpdCBjb250ZXh0LnN0ZXAoJ3Bvc3Qtc2xhY2stbWVzc2FnZXMnLCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBjbGllbnQuY2hhdC5wb3N0TWVzc2FnZShcbiAgICAgICAgYnVpbGRTbGFja1N0b3BOb3RpZmljYXRpb24oe1xuICAgICAgICAgIGNoYW5uZWwsXG4gICAgICAgICAgc291cmNlVHlwZTogZGV0YWlsLlNvdXJjZVR5cGUsXG4gICAgICAgICAgc291cmNlSWRlbnRpZmllcjogZGV0YWlsLlNvdXJjZUlkZW50aWZpZXIsXG4gICAgICAgICAgYWNjb3VudCxcbiAgICAgICAgICByZWdpb24sXG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBidWlsZFN0b3BwZWRSZXN1bHQoe1xuICAgIGZpbmFsU3RhdHVzOiBzdG9wcGVkLnN0YXR1cyxcbiAgICBhY2NvdW50LFxuICAgIHJlZ2lvbixcbiAgICBpZGVudGlmaWVyOiBkZXRhaWwuU291cmNlSWRlbnRpZmllcixcbiAgfSk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIFJEUyBzb3VyY2UgaWRlbnRpZmllciBmcm9tIHRoZSBpbnB1dCwgb3IgdW5kZWZpbmVkIHdoZW4gdGhlIGlucHV0IGlzIGludmFsaWQuXG4gKlxuICogQHBhcmFtIGlucHV0IC0gUmF3IGhhbmRsZXIgaW5wdXQuXG4gKiBAcmV0dXJucyBEQiBpbnN0YW5jZSBvciBjbHVzdGVyIGlkZW50aWZpZXIgd2hlbiBhdmFpbGFibGUuXG4gKi9cbmNvbnN0IHNvdXJjZUlkZW50aWZpZXJPZiA9IChpbnB1dDogdW5rbm93bik6IHN0cmluZyB8IHVuZGVmaW5lZCA9PiB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIG5vcm1hbGl6ZUlucHV0KGlucHV0KS5ldmVudC5kZXRhaWwuU291cmNlSWRlbnRpZmllcjtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufTtcblxuLyoqXG4gKiBSdW5zIHtAbGluayBwcm9jZXNzQXV0b1N0YXJ0UHJldmVudH0gYW5kIGxvZ3Mge0BsaW5rIEFVVE9fU1RBUlRfUFJFVkVOVF9GQUlMRURfTE9HX1RFUk19IGJlZm9yZSByZXRocm93aW5nLFxuICogYmVjYXVzZSBhIGZhaWxlZCBkdXJhYmxlIGV4ZWN1dGlvbiBkb2VzIG5vdCByYWlzZSB0aGUgTGFtYmRhIGBFcnJvcnNgIG1ldHJpYy5cbiAqXG4gKiBAcGFyYW0gaW5wdXQgLSBgeyBldmVudCwgcGFyYW1zIH1gIGZyb20gRXZlbnRCcmlkZ2UgSW5wdXRUcmFuc2Zvcm1lci5cbiAqIEBwYXJhbSBjb250ZXh0IC0gRHVyYWJsZSBleGVjdXRpb24gY29udGV4dCBmb3Igc3RlcHMgYW5kIHdhaXRzLlxuICogQHJldHVybnMge0BsaW5rIFN0b3BwZWRSZXN1bHR9IG9yIHtAbGluayBOb09wUmVzdWx0fS5cbiAqIEB0aHJvd3MgVGhlIGVycm9yIGZyb20ge0BsaW5rIHByb2Nlc3NBdXRvU3RhcnRQcmV2ZW50fS5cbiAqL1xuY29uc3QgcHJvY2Vzc0F1dG9TdGFydFByZXZlbnRXaXRoRmFpbHVyZUxvZyA9IGFzeW5jIChcbiAgaW5wdXQ6IHVua25vd24sXG4gIGNvbnRleHQ6IER1cmFibGVDb250ZXh0LFxuKTogUHJvbWlzZTxTdG9wcGVkUmVzdWx0IHwgTm9PcFJlc3VsdD4gPT4ge1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBwcm9jZXNzQXV0b1N0YXJ0UHJldmVudChpbnB1dCwgY29udGV4dCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihBVVRPX1NUQVJUX1BSRVZFTlRfRkFJTEVEX0xPR19URVJNLCB7XG4gICAgICBpZGVudGlmaWVyOiBzb3VyY2VJZGVudGlmaWVyT2YoaW5wdXQpLFxuICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvciksXG4gICAgfSk7XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cbn07XG5cbi8qKiBMYW1iZGEgZW50cnkgcG9pbnQ6IHtAbGluayBwcm9jZXNzQXV0b1N0YXJ0UHJldmVudH0gd3JhcHBlZCB3aXRoIHRoZSBmYWlsdXJlIGxvZyBhbmQgZHVyYWJsZSBleGVjdXRpb24uICovXG5leHBvcnQgY29uc3QgaGFuZGxlciA9IHdpdGhEdXJhYmxlRXhlY3V0aW9uKHByb2Nlc3NBdXRvU3RhcnRQcmV2ZW50V2l0aEZhaWx1cmVMb2cpO1xuIl19
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
* Pure helpers for the RDS auto-start prevent Lambda.
|
|
3
3
|
* No AWS SDK, Durable context, env, or clock dependencies.
|
|
4
4
|
*/
|
|
5
|
+
import { DB_CLUSTER_AUTO_START_EVENT, DB_INSTANCE_AUTO_START_EVENT, RDS_EVENT_SOURCE } from '../../settings/consts';
|
|
5
6
|
/**
|
|
6
7
|
* Detail payload of an RDS auto-start event from EventBridge.
|
|
7
8
|
*/
|
|
8
9
|
export interface RdsAutoStartDetail {
|
|
9
10
|
/** Event ID: RDS-EVENT-0154 (DB instance) or RDS-EVENT-0153 (DB cluster). */
|
|
10
|
-
EventID:
|
|
11
|
+
EventID: typeof DB_INSTANCE_AUTO_START_EVENT.eventId | typeof DB_CLUSTER_AUTO_START_EVENT.eventId;
|
|
11
12
|
/** Resource type that emitted the event. */
|
|
12
|
-
SourceType:
|
|
13
|
+
SourceType: typeof DB_INSTANCE_AUTO_START_EVENT.sourceType | typeof DB_CLUSTER_AUTO_START_EVENT.sourceType;
|
|
13
14
|
/** ARN of the DB instance or cluster. */
|
|
14
15
|
SourceArn: string;
|
|
15
16
|
/** DB instance or cluster identifier from the event. */
|
|
@@ -19,8 +20,8 @@ export interface RdsAutoStartDetail {
|
|
|
19
20
|
* RDS auto-start event as received from EventBridge.
|
|
20
21
|
*/
|
|
21
22
|
export interface RdsAutoStartEvent {
|
|
22
|
-
'detail-type':
|
|
23
|
-
'source':
|
|
23
|
+
'detail-type': typeof DB_INSTANCE_AUTO_START_EVENT.detailType | typeof DB_CLUSTER_AUTO_START_EVENT.detailType;
|
|
24
|
+
'source': typeof RDS_EVENT_SOURCE;
|
|
24
25
|
'detail': RdsAutoStartDetail;
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
@@ -97,6 +98,12 @@ export interface StopWait {
|
|
|
97
98
|
}
|
|
98
99
|
/** Result of a durable waitStrategy. */
|
|
99
100
|
export type WaitStrategyResult = ContinueWait | StopWait;
|
|
101
|
+
/** RDS statuses the handler branches on, plus the fallback when a describe returns no resource. */
|
|
102
|
+
export declare const DB_STATUS: {
|
|
103
|
+
readonly AVAILABLE: "available";
|
|
104
|
+
readonly STOPPED: "stopped";
|
|
105
|
+
readonly UNKNOWN: "unknown";
|
|
106
|
+
};
|
|
100
107
|
/** Minutes between describe calls while a status is transitional or stopping. */
|
|
101
108
|
export declare const WAIT_INTERVAL_MINUTES = 5;
|
|
102
109
|
/**
|
|
@@ -114,8 +121,8 @@ export declare const isTransitionalStatus: (status: string) => boolean;
|
|
|
114
121
|
/**
|
|
115
122
|
* Type guard for Slack credentials returned by `secretFetcher.getSecretValue`.
|
|
116
123
|
*
|
|
117
|
-
* aws-lambda-secret-fetcher ^0.
|
|
118
|
-
* falls back to the raw string on invalid JSON, so callers must validate shape.
|
|
124
|
+
* aws-lambda-secret-fetcher ^0.10 parses a string SecretString as JSON (already parsed values are
|
|
125
|
+
* returned as-is) and falls back to the raw string on invalid JSON, so callers must validate shape.
|
|
119
126
|
*
|
|
120
127
|
* @param value - Value returned from the secret fetcher.
|
|
121
128
|
* @returns Whether value is a SlackSecret with non-empty token and channel.
|
|
@@ -160,6 +167,17 @@ export declare const isDbInstanceAutoStart: (detailType: RdsAutoStartEvent["deta
|
|
|
160
167
|
* @returns True for RDS-EVENT-0153 on a cluster.
|
|
161
168
|
*/
|
|
162
169
|
export declare const isDbClusterAutoStart: (detailType: RdsAutoStartEvent["detail-type"], detail: RdsAutoStartDetail) => boolean;
|
|
170
|
+
/** RDS resource type targeted by a supported auto-start event. */
|
|
171
|
+
export type ResourceKind = 'instance' | 'cluster';
|
|
172
|
+
/**
|
|
173
|
+
* Resolves which RDS resource type a supported auto-start event targets.
|
|
174
|
+
*
|
|
175
|
+
* @param detailType - EventBridge detail-type.
|
|
176
|
+
* @param detail - RDS event detail.
|
|
177
|
+
* @returns `instance` for RDS-EVENT-0154 on a DB instance; `cluster` for RDS-EVENT-0153 on a cluster.
|
|
178
|
+
* @throws When the detail-type, SourceType, and EventID do not form a supported auto-start event.
|
|
179
|
+
*/
|
|
180
|
+
export declare const resolveResourceKind: (detailType: RdsAutoStartEvent["detail-type"], detail: RdsAutoStartDetail) => ResourceKind;
|
|
163
181
|
/**
|
|
164
182
|
* Wait strategy while describing until the resource leaves transitional statuses.
|
|
165
183
|
*
|
|
@@ -190,10 +208,11 @@ export type AfterTagMatchDecision = {
|
|
|
190
208
|
/**
|
|
191
209
|
* Decides the next action when tags matched and StopDB* has not been called yet.
|
|
192
210
|
*
|
|
193
|
-
* @param
|
|
194
|
-
* @returns Stop when `available`; no-op when already `stopped`; otherwise error
|
|
211
|
+
* @param state - Status and identifier from the first describe after leaving transitional states.
|
|
212
|
+
* @returns Stop when `available`; no-op when already `stopped`; otherwise an error naming the
|
|
213
|
+
* identifier and status, because StopDB* cannot be called from any other status.
|
|
195
214
|
*/
|
|
196
|
-
export declare const decideAfterTagMatch: (
|
|
215
|
+
export declare const decideAfterTagMatch: (state: WaitState) => AfterTagMatchDecision;
|
|
197
216
|
/**
|
|
198
217
|
* Builds the no-op result used when tags do not match.
|
|
199
218
|
*
|