@middy/ssm 5.1.0 → 5.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.
Files changed (2) hide show
  1. package/index.js +191 -143
  2. package/package.json +4 -4
package/index.js CHANGED
@@ -1,148 +1,196 @@
1
- import { canPrefetch, createPrefetchClient, createClient, processCache, getCache, modifyCache, jsonSafeParse, getInternal, sanitizeKey } from '@middy/util';
2
- import { SSMClient, GetParametersCommand, GetParametersByPathCommand } from '@aws-sdk/client-ssm';
3
- const awsRequestLimit = 10;
1
+ import {
2
+ canPrefetch,
3
+ createPrefetchClient,
4
+ createClient,
5
+ processCache,
6
+ getCache,
7
+ modifyCache,
8
+ jsonSafeParse,
9
+ getInternal,
10
+ sanitizeKey,
11
+ catchInvalidSignatureException
12
+ } from '../util/index.js'
13
+ import {
14
+ SSMClient,
15
+ GetParametersCommand,
16
+ GetParametersByPathCommand
17
+ } from '@aws-sdk/client-ssm'
18
+
19
+ const awsRequestLimit = 10
4
20
  const defaults = {
5
- AwsClient: SSMClient,
6
- awsClientOptions: {},
7
- awsClientAssumeRole: undefined,
8
- awsClientCapture: undefined,
9
- fetchData: {},
10
- disablePrefetch: false,
11
- cacheKey: 'ssm',
12
- cacheKeyExpiry: {},
13
- cacheExpiry: -1,
14
- setToContext: false
15
- };
16
- const ssmMiddleware = (opts = {})=>{
17
- const options = {
18
- ...defaults,
19
- ...opts
20
- };
21
- const fetch = (request, cachedValues)=>{
22
- return {
23
- ...fetchSingle(request, cachedValues),
24
- ...fetchByPath(request, cachedValues)
25
- };
26
- };
27
- const fetchSingle = (request, cachedValues = {})=>{
28
- const values = {};
29
- let batchReq = null;
30
- let batchInternalKeys = [];
31
- let batchFetchKeys = [];
32
- const namedKeys = [];
33
- const internalKeys = Object.keys(options.fetchData);
34
- const fetchKeys = Object.values(options.fetchData);
35
- for (const internalKey of internalKeys){
36
- if (cachedValues[internalKey]) continue;
37
- if (options.fetchData[internalKey].substr(-1) === '/') continue;
38
- namedKeys.push(internalKey);
39
- }
40
- for (const [idx, internalKey] of namedKeys.entries()){
41
- const fetchKey = options.fetchData[internalKey];
42
- batchInternalKeys.push(internalKey);
43
- batchFetchKeys.push(fetchKey);
44
- if ((!idx || (idx + 1) % awsRequestLimit !== 0) && !(idx + 1 === namedKeys.length)) {
45
- continue;
46
- }
47
- batchReq = client.send(new GetParametersCommand({
48
- Names: batchFetchKeys,
49
- WithDecryption: true
50
- })).then((resp)=>{
51
- return Object.assign(...(resp.InvalidParameters ?? []).map((fetchKey)=>{
52
- return {
53
- [fetchKey]: new Promise(()=>{
54
- const internalKey = internalKeys[fetchKeys.indexOf(fetchKey)];
55
- const value = getCache(options.cacheKey).value ?? {};
56
- value[internalKey] = undefined;
57
- modifyCache(options.cacheKey, value);
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
- });
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
+
33
+ const ssmMiddleware = (opts = {}) => {
34
+ const options = { ...defaults, ...opts }
35
+
36
+ const fetch = (request, cachedValues) => {
37
+ return {
38
+ ...fetchSingle(request, cachedValues),
39
+ ...fetchByPath(request, cachedValues)
40
+ }
41
+ }
42
+
43
+ const fetchSingle = (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 fetchByPath = (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] = fetchPath(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 fetchPath = (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)
80
150
  }
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,
107
- WithDecryption: true
108
- })).then((resp)=>{
109
- Object.assign(values, ...resp.Parameters.map((param)=>{
110
- return {
111
- [sanitizeKey(param.Name.replace(path, ''))]: parseValue(param)
112
- };
113
- }));
114
- if (resp.NextToken) return fetchPath(path, resp.NextToken, values);
115
- return values;
116
- });
117
- };
118
- const parseValue = (param)=>{
119
- if (param.Type === 'StringList') {
120
- return param.Value.split(',');
121
- }
122
- return jsonSafeParse(param.Value);
123
- };
124
- let client;
125
- if (canPrefetch(options)) {
126
- client = createPrefetchClient(options);
127
- processCache(options, fetch);
151
+ })
152
+ )
153
+ if (resp.NextToken) return fetchPath(path, resp.NextToken, values)
154
+ return values
155
+ })
156
+ }
157
+
158
+ const parseValue = (param) => {
159
+ if (param.Type === 'StringList') {
160
+ return param.Value.split(',')
128
161
  }
129
- const ssmMiddlewareBefore = async (request)=>{
130
- if (!client) {
131
- client = await createClient(options, request);
132
- }
133
- const { value } = processCache(options, fetch, request);
134
- Object.assign(request.internal, value);
135
- if (options.setToContext) {
136
- const data = await getInternal(Object.keys(options.fetchData), request);
137
- Object.assign(request.context, data);
138
- }
139
- };
140
- return {
141
- before: ssmMiddlewareBefore
142
- };
143
- };
144
- export default ssmMiddleware;
145
- export function ssmParam(name) {
146
- return name;
162
+ return jsonSafeParse(param.Value)
163
+ }
164
+
165
+ let client
166
+ if (canPrefetch(options)) {
167
+ client = createPrefetchClient(options)
168
+ processCache(options, fetch)
169
+ }
170
+
171
+ const ssmMiddlewareBefore = async (request) => {
172
+ if (!client) {
173
+ client = await createClient(options, request)
174
+ }
175
+
176
+ const { value } = processCache(options, fetch, request)
177
+
178
+ Object.assign(request.internal, value)
179
+
180
+ if (options.setToContext) {
181
+ const data = await getInternal(Object.keys(options.fetchData), request)
182
+ Object.assign(request.context, data)
183
+ }
184
+ }
185
+
186
+ return {
187
+ before: ssmMiddlewareBefore
188
+ }
147
189
  }
148
190
 
191
+ export default ssmMiddleware
192
+
193
+ // used for TS type inference (see index.d.ts)
194
+ export function ssmParam (name) {
195
+ return name
196
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@middy/ssm",
3
- "version": "5.1.0",
3
+ "version": "5.2.1",
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.1.0"
63
+ "@middy/util": "5.2.1"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@aws-sdk/client-ssm": "^3.0.0",
67
- "@middy/core": "5.1.0",
67
+ "@middy/core": "5.2.1",
68
68
  "@types/aws-lambda": "^8.10.101",
69
69
  "aws-xray-sdk": "^3.3.3"
70
70
  },
71
- "gitHead": "bbdaf5843914921804ba085dd58117273febe6b5"
71
+ "gitHead": "4d55da221b9165b4b3e59a12632fd40a149a1e92"
72
72
  }