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