@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.
Files changed (2) hide show
  1. package/index.js +190 -143
  2. package/package.json +4 -4
package/index.js CHANGED
@@ -1,148 +1,195 @@
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
+ } 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
- 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
- });
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
- })).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);
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
- 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;
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",
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.3"
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.3",
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": "87660575a7ac2b52e4153c407a4c63c9449dcd0d"
71
+ "gitHead": "2d9096a49cd8fb62359517be96d6c93609df41f0"
72
72
  }