@middy/ssm 6.1.6 → 6.2.1
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/index.d.ts +36 -30
- package/index.js +190 -188
- package/package.json +71 -74
package/index.d.ts
CHANGED
|
@@ -1,40 +1,46 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import type { SSMClient, SSMClientConfig } from "@aws-sdk/client-ssm";
|
|
2
|
+
import type middy from "@middy/core";
|
|
3
|
+
import type { Options as MiddyOptions } from "@middy/util";
|
|
4
|
+
import type { Context as LambdaContext } from "aws-lambda";
|
|
5
5
|
|
|
6
|
-
export type ParamType<T> = string & { __returnType?: T }
|
|
7
|
-
export declare function ssmParam<T>
|
|
6
|
+
export type ParamType<T> = string & { __returnType?: T };
|
|
7
|
+
export declare function ssmParam<T>(path: string): ParamType<T>;
|
|
8
8
|
|
|
9
9
|
export interface SSMOptions<AwsSSMClient = SSMClient>
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
extends Omit<MiddyOptions<AwsSSMClient, SSMClientConfig>, "fetchData"> {
|
|
11
|
+
fetchData?: { [key: string]: string | ParamType<unknown> };
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export type Context<TOptions extends SSMOptions | undefined> =
|
|
15
|
-
TOptions extends { setToContext: true }
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
TOptions extends { setToContext: true }
|
|
16
|
+
? TOptions extends { fetchData: infer TFetchData }
|
|
17
|
+
? LambdaContext & {
|
|
18
|
+
[Key in keyof TFetchData]: TFetchData[Key] extends ParamType<infer T>
|
|
19
|
+
? T
|
|
20
|
+
: unknown;
|
|
21
|
+
}
|
|
22
|
+
: never
|
|
23
|
+
: LambdaContext;
|
|
24
24
|
|
|
25
25
|
export type Internal<TOptions extends SSMOptions | undefined> =
|
|
26
|
-
TOptions extends SSMOptions
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
TOptions extends SSMOptions
|
|
27
|
+
? TOptions extends { fetchData: infer TFetchData }
|
|
28
|
+
? {
|
|
29
|
+
[Key in keyof TFetchData]: TFetchData[Key] extends ParamType<infer T>
|
|
30
|
+
? T
|
|
31
|
+
: unknown;
|
|
32
|
+
}
|
|
33
|
+
: {}
|
|
34
|
+
: {};
|
|
35
35
|
|
|
36
|
-
declare function ssm<TOptions extends SSMOptions>
|
|
37
|
-
|
|
38
|
-
): middy.MiddlewareObj<
|
|
36
|
+
declare function ssm<TOptions extends SSMOptions>(
|
|
37
|
+
options?: TOptions,
|
|
38
|
+
): middy.MiddlewareObj<
|
|
39
|
+
unknown,
|
|
40
|
+
any,
|
|
41
|
+
Error,
|
|
42
|
+
Context<TOptions>,
|
|
43
|
+
Internal<TOptions>
|
|
44
|
+
>;
|
|
39
45
|
|
|
40
|
-
export default ssm
|
|
46
|
+
export default ssm;
|
package/index.js
CHANGED
|
@@ -1,196 +1,198 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
getCache,
|
|
7
|
-
modifyCache,
|
|
8
|
-
jsonSafeParse,
|
|
9
|
-
getInternal,
|
|
10
|
-
sanitizeKey,
|
|
11
|
-
catchInvalidSignatureException
|
|
12
|
-
} from '../util/index.js'
|
|
2
|
+
GetParametersByPathCommand,
|
|
3
|
+
GetParametersCommand,
|
|
4
|
+
SSMClient,
|
|
5
|
+
} from "@aws-sdk/client-ssm";
|
|
13
6
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
canPrefetch,
|
|
8
|
+
catchInvalidSignatureException,
|
|
9
|
+
createClient,
|
|
10
|
+
createPrefetchClient,
|
|
11
|
+
getCache,
|
|
12
|
+
getInternal,
|
|
13
|
+
jsonSafeParse,
|
|
14
|
+
modifyCache,
|
|
15
|
+
processCache,
|
|
16
|
+
sanitizeKey,
|
|
17
|
+
} from "../util/index.js";
|
|
18
|
+
|
|
19
|
+
const awsRequestLimit = 10;
|
|
20
20
|
const defaults = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
21
|
+
AwsClient: SSMClient, // Allow for XRay
|
|
22
|
+
awsClientOptions: {},
|
|
23
|
+
awsClientAssumeRole: undefined,
|
|
24
|
+
awsClientCapture: undefined,
|
|
25
|
+
fetchData: {}, // { contextKey: fetchKey, contextPrefix: fetchPath/ }
|
|
26
|
+
disablePrefetch: false,
|
|
27
|
+
cacheKey: "ssm",
|
|
28
|
+
cacheKeyExpiry: {},
|
|
29
|
+
cacheExpiry: -1,
|
|
30
|
+
setToContext: false,
|
|
31
|
+
};
|
|
32
32
|
|
|
33
33
|
const ssmMiddleware = (opts = {}) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
34
|
+
const options = { ...defaults, ...opts };
|
|
35
|
+
|
|
36
|
+
const fetchRequest = (request, cachedValues) => {
|
|
37
|
+
return {
|
|
38
|
+
...fetchSingleRequest(request, cachedValues),
|
|
39
|
+
...fetchByPathRequest(request, cachedValues),
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const fetchSingleRequest = (request, cachedValues = {}) => {
|
|
44
|
+
const values = {};
|
|
45
|
+
let batchReq = null;
|
|
46
|
+
let batchInternalKeys = [];
|
|
47
|
+
let batchFetchKeys = [];
|
|
48
|
+
const namedKeys = [];
|
|
49
|
+
|
|
50
|
+
const internalKeys = Object.keys(options.fetchData);
|
|
51
|
+
const fetchKeys = Object.values(options.fetchData);
|
|
52
|
+
for (const internalKey of internalKeys) {
|
|
53
|
+
if (cachedValues[internalKey]) continue;
|
|
54
|
+
if (options.fetchData[internalKey].substr(-1) === "/") continue; // Skip path passed in
|
|
55
|
+
namedKeys.push(internalKey);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (const [idx, internalKey] of namedKeys.entries()) {
|
|
59
|
+
const fetchKey = options.fetchData[internalKey];
|
|
60
|
+
batchInternalKeys.push(internalKey);
|
|
61
|
+
batchFetchKeys.push(fetchKey);
|
|
62
|
+
// from the first to the batch size skip, unless it's the last entry
|
|
63
|
+
if (
|
|
64
|
+
(!idx || (idx + 1) % awsRequestLimit !== 0) &&
|
|
65
|
+
!(idx + 1 === namedKeys.length)
|
|
66
|
+
) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const command = new GetParametersCommand({
|
|
71
|
+
Names: batchFetchKeys,
|
|
72
|
+
WithDecryption: true,
|
|
73
|
+
});
|
|
74
|
+
batchReq = client
|
|
75
|
+
.send(command)
|
|
76
|
+
.catch((e) => catchInvalidSignatureException(e, client, command))
|
|
77
|
+
.then((resp) => {
|
|
78
|
+
// Don't sanitize key, mapped to set value in options
|
|
79
|
+
return Object.assign(
|
|
80
|
+
...(resp.InvalidParameters ?? []).map((fetchKey) => {
|
|
81
|
+
return {
|
|
82
|
+
[fetchKey]: new Promise(() => {
|
|
83
|
+
const internalKey = internalKeys[fetchKeys.indexOf(fetchKey)];
|
|
84
|
+
const value = getCache(options.cacheKey).value ?? {};
|
|
85
|
+
value[internalKey] = undefined;
|
|
86
|
+
modifyCache(options.cacheKey, value);
|
|
87
|
+
throw new Error(`InvalidParameter ${fetchKey}`, {
|
|
88
|
+
cause: { package: "@middy/ssm" },
|
|
89
|
+
});
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
92
|
+
}),
|
|
93
|
+
...(resp.Parameters ?? []).map((param) => {
|
|
94
|
+
return { [param.Name]: parseValue(param) };
|
|
95
|
+
}),
|
|
96
|
+
);
|
|
97
|
+
})
|
|
98
|
+
.catch((e) => {
|
|
99
|
+
const value = getCache(options.cacheKey).value ?? {};
|
|
100
|
+
value[internalKey] = undefined;
|
|
101
|
+
modifyCache(options.cacheKey, value);
|
|
102
|
+
throw e;
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
for (const internalKey of batchInternalKeys) {
|
|
106
|
+
values[internalKey] = batchReq.then((params) => {
|
|
107
|
+
return params[options.fetchData[internalKey]];
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
batchInternalKeys = [];
|
|
112
|
+
batchFetchKeys = [];
|
|
113
|
+
batchReq = null;
|
|
114
|
+
}
|
|
115
|
+
return values;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const fetchByPathRequest = (request, cachedValues = {}) => {
|
|
119
|
+
const values = {};
|
|
120
|
+
for (const internalKey in options.fetchData) {
|
|
121
|
+
if (cachedValues[internalKey]) continue;
|
|
122
|
+
const fetchKey = options.fetchData[internalKey];
|
|
123
|
+
if (fetchKey.substr(-1) !== "/") continue; // Skip not path passed in
|
|
124
|
+
values[internalKey] = fetchPathRequest(fetchKey).catch((e) => {
|
|
125
|
+
const value = getCache(options.cacheKey).value ?? {};
|
|
126
|
+
value[internalKey] = undefined;
|
|
127
|
+
modifyCache(options.cacheKey, value);
|
|
128
|
+
throw e;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return values;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const fetchPathRequest = (path, nextToken, values = {}) => {
|
|
135
|
+
const command = new GetParametersByPathCommand({
|
|
136
|
+
Path: path,
|
|
137
|
+
NextToken: nextToken,
|
|
138
|
+
Recursive: true,
|
|
139
|
+
WithDecryption: true,
|
|
140
|
+
});
|
|
141
|
+
return client
|
|
142
|
+
.send(command)
|
|
143
|
+
.catch((e) => catchInvalidSignatureException(e, client, command))
|
|
144
|
+
.then((resp) => {
|
|
145
|
+
Object.assign(
|
|
146
|
+
values,
|
|
147
|
+
...resp.Parameters.map((param) => {
|
|
148
|
+
return {
|
|
149
|
+
[sanitizeKey(param.Name.replace(path, ""))]: parseValue(param),
|
|
150
|
+
};
|
|
151
|
+
}),
|
|
152
|
+
);
|
|
153
|
+
if (resp.NextToken) {
|
|
154
|
+
return fetchPathRequest(path, resp.NextToken, values);
|
|
155
|
+
}
|
|
156
|
+
return values;
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const parseValue = (param) => {
|
|
161
|
+
if (param.Type === "StringList") {
|
|
162
|
+
return param.Value.split(",");
|
|
163
|
+
}
|
|
164
|
+
return jsonSafeParse(param.Value);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
let client;
|
|
168
|
+
if (canPrefetch(options)) {
|
|
169
|
+
client = createPrefetchClient(options);
|
|
170
|
+
processCache(options, fetchRequest);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const ssmMiddlewareBefore = async (request) => {
|
|
174
|
+
if (!client) {
|
|
175
|
+
client = await createClient(options, request);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const { value } = processCache(options, fetchRequest, request);
|
|
179
|
+
|
|
180
|
+
Object.assign(request.internal, value);
|
|
181
|
+
|
|
182
|
+
if (options.setToContext) {
|
|
183
|
+
const data = await getInternal(Object.keys(options.fetchData), request);
|
|
184
|
+
Object.assign(request.context, data);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
before: ssmMiddlewareBefore,
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
export default ssmMiddleware;
|
|
192
194
|
|
|
193
195
|
// used for TS type inference (see index.d.ts)
|
|
194
|
-
export function ssmParam
|
|
195
|
-
|
|
196
|
+
export function ssmParam(name) {
|
|
197
|
+
return name;
|
|
196
198
|
}
|
package/package.json
CHANGED
|
@@ -1,76 +1,73 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"aws-xray-sdk": "^3.3.3"
|
|
74
|
-
},
|
|
75
|
-
"gitHead": "7a6c0fbb8ab71d6a2171e678697de9f237568431"
|
|
2
|
+
"name": "@middy/ssm",
|
|
3
|
+
"version": "6.2.1",
|
|
4
|
+
"description": "SSM (EC2 Systems Manager) parameters middleware for the middy framework",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20"
|
|
8
|
+
},
|
|
9
|
+
"engineStrict": true,
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"module": "./index.js",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": {
|
|
17
|
+
"types": "./index.d.ts",
|
|
18
|
+
"default": "./index.js"
|
|
19
|
+
},
|
|
20
|
+
"require": {
|
|
21
|
+
"default": "./index.js"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"types": "index.d.ts",
|
|
26
|
+
"files": ["index.js", "index.d.ts"],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"test": "npm run test:unit && npm run test:fuzz",
|
|
29
|
+
"test:unit": "node --test",
|
|
30
|
+
"test:fuzz": "node --test index.fuzz.js",
|
|
31
|
+
"test:perf": "node --test index.perf.js"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"keywords": [
|
|
35
|
+
"Lambda",
|
|
36
|
+
"Middleware",
|
|
37
|
+
"Serverless",
|
|
38
|
+
"Framework",
|
|
39
|
+
"AWS",
|
|
40
|
+
"AWS Lambda",
|
|
41
|
+
"Middy",
|
|
42
|
+
"SSM",
|
|
43
|
+
"EC2 Systems Manager",
|
|
44
|
+
"Parameters"
|
|
45
|
+
],
|
|
46
|
+
"author": {
|
|
47
|
+
"name": "Middy contributors",
|
|
48
|
+
"url": "https://github.com/middyjs/middy/graphs/contributors"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/middyjs/middy.git",
|
|
53
|
+
"directory": "packages/ssm"
|
|
54
|
+
},
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/middyjs/middy/issues"
|
|
57
|
+
},
|
|
58
|
+
"homepage": "https://middy.js.org",
|
|
59
|
+
"funding": {
|
|
60
|
+
"type": "github",
|
|
61
|
+
"url": "https://github.com/sponsors/willfarrell"
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@middy/util": "6.2.1"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@aws-sdk/client-ssm": "^3.0.0",
|
|
68
|
+
"@middy/core": "6.2.1",
|
|
69
|
+
"@types/aws-lambda": "^8.10.101",
|
|
70
|
+
"aws-xray-sdk": "^3.3.3"
|
|
71
|
+
},
|
|
72
|
+
"gitHead": "7a6c0fbb8ab71d6a2171e678697de9f237568431"
|
|
76
73
|
}
|