@middy/ssm 5.0.0-alpha.0 → 5.0.0-alpha.2
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/README.md +3 -2
- package/index.d.ts +28 -16
- package/index.js +23 -9
- package/package.json +5 -12
- package/index.cjs +0 -145
package/README.md
CHANGED
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
<a href="https://snyk.io/test/github/middyjs/middy">
|
|
20
20
|
<img src="https://snyk.io/test/github/middyjs/middy/badge.svg" alt="Known Vulnerabilities" data-canonical-src="https://snyk.io/test/github/middyjs/middy" style="max-width:100%;">
|
|
21
21
|
</a>
|
|
22
|
-
<a href="https://
|
|
23
|
-
<img src="https://
|
|
22
|
+
<a href="https://github.com/middyjs/middy/actions/workflows/sast.yml">
|
|
23
|
+
<img src="https://github.com/middyjs/middy/actions/workflows/sast.yml/badge.svg
|
|
24
|
+
?branch=main&event=push" alt="CodeQL" style="max-width:100%;">
|
|
24
25
|
</a>
|
|
25
26
|
<a href="https://bestpractices.coreinfrastructure.org/projects/5280">
|
|
26
27
|
<img src="https://bestpractices.coreinfrastructure.org/projects/5280/badge" alt="Core Infrastructure Initiative (CII) Best Practices" style="max-width:100%;">
|
package/index.d.ts
CHANGED
|
@@ -2,27 +2,39 @@ import middy from '@middy/core'
|
|
|
2
2
|
import { Options as MiddyOptions } from '@middy/util'
|
|
3
3
|
import { Context as LambdaContext } from 'aws-lambda'
|
|
4
4
|
import { SSMClient, SSMClientConfig } from '@aws-sdk/client-ssm'
|
|
5
|
-
import { JsonValue } from 'type-fest'
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
export type ParamType<T> = string & { __returnType?: T }
|
|
7
|
+
export declare function ssmParam<T> (path: string): ParamType<T>
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export type Context<TOptions extends Options | undefined> = TOptions extends {
|
|
14
|
-
setToContext: true
|
|
9
|
+
export interface SSMOptions<AwsSSMClient = SSMClient>
|
|
10
|
+
extends Omit<MiddyOptions<AwsSSMClient, SSMClientConfig>, 'fetchData'> {
|
|
11
|
+
fetchData?: { [key: string]: string | ParamType<unknown> }
|
|
15
12
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
?
|
|
21
|
-
|
|
13
|
+
|
|
14
|
+
export type Context<TOptions extends SSMOptions | undefined> =
|
|
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
|
|
22
23
|
: LambdaContext
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
export type Internal<TOptions extends SSMOptions | undefined> =
|
|
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
|
+
|
|
36
|
+
declare function ssm<TOptions extends SSMOptions> (
|
|
25
37
|
options?: TOptions
|
|
26
|
-
): middy.MiddlewareObj<unknown, any, Error, Context<TOptions>>
|
|
38
|
+
): middy.MiddlewareObj<unknown, any, Error, Context<TOptions>, Internal<TOptions>>
|
|
27
39
|
|
|
28
40
|
export default ssm
|
package/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const defaults = {
|
|
|
9
9
|
fetchData: {},
|
|
10
10
|
disablePrefetch: false,
|
|
11
11
|
cacheKey: 'ssm',
|
|
12
|
+
cacheKeyExpiry: {},
|
|
12
13
|
cacheExpiry: -1,
|
|
13
14
|
setToContext: false
|
|
14
15
|
};
|
|
@@ -28,21 +29,27 @@ const ssmMiddleware = (opts = {})=>{
|
|
|
28
29
|
let batchReq = null;
|
|
29
30
|
let batchInternalKeys = [];
|
|
30
31
|
let batchFetchKeys = [];
|
|
32
|
+
const namedKeys = [];
|
|
31
33
|
const internalKeys = Object.keys(options.fetchData);
|
|
32
34
|
const fetchKeys = Object.values(options.fetchData);
|
|
33
|
-
for (const
|
|
35
|
+
for (const internalKey of internalKeys){
|
|
34
36
|
if (cachedValues[internalKey]) continue;
|
|
37
|
+
if (options.fetchData[internalKey].substr(-1) === '/') continue; // Skip path passed in
|
|
38
|
+
namedKeys.push(internalKey);
|
|
39
|
+
}
|
|
40
|
+
for (const [idx, internalKey] of namedKeys.entries()){
|
|
35
41
|
const fetchKey = options.fetchData[internalKey];
|
|
36
|
-
if (fetchKey.substr(-1) === '/') continue;
|
|
37
42
|
batchInternalKeys.push(internalKey);
|
|
38
43
|
batchFetchKeys.push(fetchKey);
|
|
39
|
-
|
|
44
|
+
// from the first to the batch size skip, unless it's the last entry
|
|
45
|
+
if ((!idx || (idx + 1) % awsRequestLimit !== 0) && !(idx + 1 === namedKeys.length)) {
|
|
40
46
|
continue;
|
|
41
47
|
}
|
|
42
48
|
batchReq = client.send(new GetParametersCommand({
|
|
43
49
|
Names: batchFetchKeys,
|
|
44
50
|
WithDecryption: true
|
|
45
51
|
})).then((resp)=>{
|
|
52
|
+
// Don't sanitize key, mapped to set value in options
|
|
46
53
|
return Object.assign(...(resp.InvalidParameters ?? []).map((fetchKey)=>{
|
|
47
54
|
return {
|
|
48
55
|
[fetchKey]: new Promise(()=>{
|
|
@@ -50,7 +57,11 @@ const ssmMiddleware = (opts = {})=>{
|
|
|
50
57
|
const value = getCache(options.cacheKey).value ?? {};
|
|
51
58
|
value[internalKey] = undefined;
|
|
52
59
|
modifyCache(options.cacheKey, value);
|
|
53
|
-
throw new Error('
|
|
60
|
+
throw new Error('InvalidParameter ' + fetchKey, {
|
|
61
|
+
cause: {
|
|
62
|
+
package: '@middy/ssm'
|
|
63
|
+
}
|
|
64
|
+
});
|
|
54
65
|
})
|
|
55
66
|
};
|
|
56
67
|
}), ...(resp.Parameters ?? []).map((param)=>{
|
|
@@ -80,7 +91,7 @@ const ssmMiddleware = (opts = {})=>{
|
|
|
80
91
|
for(const internalKey in options.fetchData){
|
|
81
92
|
if (cachedValues[internalKey]) continue;
|
|
82
93
|
const fetchKey = options.fetchData[internalKey];
|
|
83
|
-
if (fetchKey.substr(-1) !== '/') continue;
|
|
94
|
+
if (fetchKey.substr(-1) !== '/') continue; // Skip not path passed in
|
|
84
95
|
values[internalKey] = fetchPath(fetchKey).catch((e)=>{
|
|
85
96
|
const value = getCache(options.cacheKey).value ?? {};
|
|
86
97
|
value[internalKey] = undefined;
|
|
@@ -112,26 +123,29 @@ const ssmMiddleware = (opts = {})=>{
|
|
|
112
123
|
}
|
|
113
124
|
return jsonSafeParse(param.Value);
|
|
114
125
|
};
|
|
115
|
-
let
|
|
126
|
+
let client;
|
|
116
127
|
if (canPrefetch(options)) {
|
|
117
128
|
client = createPrefetchClient(options);
|
|
118
|
-
|
|
129
|
+
processCache(options, fetch);
|
|
119
130
|
}
|
|
120
131
|
const ssmMiddlewareBefore = async (request)=>{
|
|
121
132
|
if (!client) {
|
|
122
133
|
client = await createClient(options, request);
|
|
123
134
|
}
|
|
124
|
-
const { value
|
|
135
|
+
const { value } = processCache(options, fetch, request);
|
|
125
136
|
Object.assign(request.internal, value);
|
|
126
137
|
if (options.setToContext) {
|
|
127
138
|
const data = await getInternal(Object.keys(options.fetchData), request);
|
|
128
139
|
Object.assign(request.context, data);
|
|
129
140
|
}
|
|
130
|
-
prefetch = null;
|
|
131
141
|
};
|
|
132
142
|
return {
|
|
133
143
|
before: ssmMiddlewareBefore
|
|
134
144
|
};
|
|
135
145
|
};
|
|
136
146
|
export default ssmMiddleware;
|
|
147
|
+
// used for TS type inference (see index.d.ts)
|
|
148
|
+
export function ssmParam(name) {
|
|
149
|
+
return name;
|
|
150
|
+
}
|
|
137
151
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@middy/ssm",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.2",
|
|
4
4
|
"description": "SSM (EC2 Systems Manager) parameters middleware for the middy framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -10,24 +10,18 @@
|
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
13
|
-
"main": "./index.cjs",
|
|
14
13
|
"module": "./index.js",
|
|
15
14
|
"exports": {
|
|
16
15
|
".": {
|
|
17
16
|
"import": {
|
|
18
17
|
"types": "./index.d.ts",
|
|
19
18
|
"default": "./index.js"
|
|
20
|
-
},
|
|
21
|
-
"require": {
|
|
22
|
-
"types": "./index.d.ts",
|
|
23
|
-
"default": "./index.cjs"
|
|
24
19
|
}
|
|
25
20
|
}
|
|
26
21
|
},
|
|
27
22
|
"types": "index.d.ts",
|
|
28
23
|
"files": [
|
|
29
24
|
"index.js",
|
|
30
|
-
"index.cjs",
|
|
31
25
|
"index.d.ts"
|
|
32
26
|
],
|
|
33
27
|
"scripts": {
|
|
@@ -66,14 +60,13 @@
|
|
|
66
60
|
"url": "https://github.com/sponsors/willfarrell"
|
|
67
61
|
},
|
|
68
62
|
"dependencies": {
|
|
69
|
-
"@middy/util": "5.0.0-alpha.
|
|
63
|
+
"@middy/util": "5.0.0-alpha.2"
|
|
70
64
|
},
|
|
71
65
|
"devDependencies": {
|
|
72
66
|
"@aws-sdk/client-ssm": "^3.0.0",
|
|
73
|
-
"@middy/core": "5.0.0-alpha.
|
|
67
|
+
"@middy/core": "5.0.0-alpha.2",
|
|
74
68
|
"@types/aws-lambda": "^8.10.101",
|
|
75
|
-
"aws-xray-sdk": "^3.3.3"
|
|
76
|
-
"type-fest": "^3.0.0"
|
|
69
|
+
"aws-xray-sdk": "^3.3.3"
|
|
77
70
|
},
|
|
78
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "ebce8d5df8783077fa49ba62ee9be20e8486a7f1"
|
|
79
72
|
}
|
package/index.cjs
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(module, "exports", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: ()=>_default
|
|
8
|
-
});
|
|
9
|
-
const _util = require("@middy/util");
|
|
10
|
-
const _clientSsm = require("@aws-sdk/client-ssm");
|
|
11
|
-
const awsRequestLimit = 10;
|
|
12
|
-
const defaults = {
|
|
13
|
-
AwsClient: _clientSsm.SSMClient,
|
|
14
|
-
awsClientOptions: {},
|
|
15
|
-
awsClientAssumeRole: undefined,
|
|
16
|
-
awsClientCapture: undefined,
|
|
17
|
-
fetchData: {},
|
|
18
|
-
disablePrefetch: false,
|
|
19
|
-
cacheKey: 'ssm',
|
|
20
|
-
cacheExpiry: -1,
|
|
21
|
-
setToContext: false
|
|
22
|
-
};
|
|
23
|
-
const ssmMiddleware = (opts = {})=>{
|
|
24
|
-
const options = {
|
|
25
|
-
...defaults,
|
|
26
|
-
...opts
|
|
27
|
-
};
|
|
28
|
-
const fetch = (request, cachedValues)=>{
|
|
29
|
-
return {
|
|
30
|
-
...fetchSingle(request, cachedValues),
|
|
31
|
-
...fetchByPath(request, cachedValues)
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
const fetchSingle = (request, cachedValues = {})=>{
|
|
35
|
-
const values = {};
|
|
36
|
-
let batchReq = null;
|
|
37
|
-
let batchInternalKeys = [];
|
|
38
|
-
let batchFetchKeys = [];
|
|
39
|
-
const internalKeys = Object.keys(options.fetchData);
|
|
40
|
-
const fetchKeys = Object.values(options.fetchData);
|
|
41
|
-
for (const [idx, internalKey] of internalKeys.entries()){
|
|
42
|
-
if (cachedValues[internalKey]) continue;
|
|
43
|
-
const fetchKey = options.fetchData[internalKey];
|
|
44
|
-
if (fetchKey.substr(-1) === '/') continue;
|
|
45
|
-
batchInternalKeys.push(internalKey);
|
|
46
|
-
batchFetchKeys.push(fetchKey);
|
|
47
|
-
if ((!idx || (idx + 1) % awsRequestLimit !== 0) && !(idx + 1 === internalKeys.length)) {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
batchReq = client.send(new _clientSsm.GetParametersCommand({
|
|
51
|
-
Names: batchFetchKeys,
|
|
52
|
-
WithDecryption: true
|
|
53
|
-
})).then((resp)=>{
|
|
54
|
-
return Object.assign(...(resp.InvalidParameters ?? []).map((fetchKey)=>{
|
|
55
|
-
return {
|
|
56
|
-
[fetchKey]: new Promise(()=>{
|
|
57
|
-
const internalKey = internalKeys[fetchKeys.indexOf(fetchKey)];
|
|
58
|
-
const value = (0, _util.getCache)(options.cacheKey).value ?? {};
|
|
59
|
-
value[internalKey] = undefined;
|
|
60
|
-
(0, _util.modifyCache)(options.cacheKey, value);
|
|
61
|
-
throw new Error('[ssm] InvalidParameter ' + fetchKey);
|
|
62
|
-
})
|
|
63
|
-
};
|
|
64
|
-
}), ...(resp.Parameters ?? []).map((param)=>{
|
|
65
|
-
return {
|
|
66
|
-
[param.Name]: parseValue(param)
|
|
67
|
-
};
|
|
68
|
-
}));
|
|
69
|
-
}).catch((e)=>{
|
|
70
|
-
const value = (0, _util.getCache)(options.cacheKey).value ?? {};
|
|
71
|
-
value[internalKey] = undefined;
|
|
72
|
-
(0, _util.modifyCache)(options.cacheKey, value);
|
|
73
|
-
throw e;
|
|
74
|
-
});
|
|
75
|
-
for (const internalKey of batchInternalKeys){
|
|
76
|
-
values[internalKey] = batchReq.then((params)=>{
|
|
77
|
-
return params[options.fetchData[internalKey]];
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
batchInternalKeys = [];
|
|
81
|
-
batchFetchKeys = [];
|
|
82
|
-
batchReq = null;
|
|
83
|
-
}
|
|
84
|
-
return values;
|
|
85
|
-
};
|
|
86
|
-
const fetchByPath = (request, cachedValues = {})=>{
|
|
87
|
-
const values = {};
|
|
88
|
-
for(const internalKey in options.fetchData){
|
|
89
|
-
if (cachedValues[internalKey]) continue;
|
|
90
|
-
const fetchKey = options.fetchData[internalKey];
|
|
91
|
-
if (fetchKey.substr(-1) !== '/') continue;
|
|
92
|
-
values[internalKey] = fetchPath(fetchKey).catch((e)=>{
|
|
93
|
-
const value = (0, _util.getCache)(options.cacheKey).value ?? {};
|
|
94
|
-
value[internalKey] = undefined;
|
|
95
|
-
(0, _util.modifyCache)(options.cacheKey, value);
|
|
96
|
-
throw e;
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
return values;
|
|
100
|
-
};
|
|
101
|
-
const fetchPath = (path, nextToken, values = {})=>{
|
|
102
|
-
return client.send(new _clientSsm.GetParametersByPathCommand({
|
|
103
|
-
Path: path,
|
|
104
|
-
NextToken: nextToken,
|
|
105
|
-
Recursive: true,
|
|
106
|
-
WithDecryption: true
|
|
107
|
-
})).then((resp)=>{
|
|
108
|
-
Object.assign(values, ...resp.Parameters.map((param)=>{
|
|
109
|
-
return {
|
|
110
|
-
[(0, _util.sanitizeKey)(param.Name.replace(path, ''))]: parseValue(param)
|
|
111
|
-
};
|
|
112
|
-
}));
|
|
113
|
-
if (resp.NextToken) return fetchPath(path, resp.NextToken, values);
|
|
114
|
-
return values;
|
|
115
|
-
});
|
|
116
|
-
};
|
|
117
|
-
const parseValue = (param)=>{
|
|
118
|
-
if (param.Type === 'StringList') {
|
|
119
|
-
return param.Value.split(',');
|
|
120
|
-
}
|
|
121
|
-
return (0, _util.jsonSafeParse)(param.Value);
|
|
122
|
-
};
|
|
123
|
-
let prefetch, client;
|
|
124
|
-
if ((0, _util.canPrefetch)(options)) {
|
|
125
|
-
client = (0, _util.createPrefetchClient)(options);
|
|
126
|
-
prefetch = (0, _util.processCache)(options, fetch);
|
|
127
|
-
}
|
|
128
|
-
const ssmMiddlewareBefore = async (request)=>{
|
|
129
|
-
if (!client) {
|
|
130
|
-
client = await (0, _util.createClient)(options, request);
|
|
131
|
-
}
|
|
132
|
-
const { value } = prefetch ?? (0, _util.processCache)(options, fetch, request);
|
|
133
|
-
Object.assign(request.internal, value);
|
|
134
|
-
if (options.setToContext) {
|
|
135
|
-
const data = await (0, _util.getInternal)(Object.keys(options.fetchData), request);
|
|
136
|
-
Object.assign(request.context, data);
|
|
137
|
-
}
|
|
138
|
-
prefetch = null;
|
|
139
|
-
};
|
|
140
|
-
return {
|
|
141
|
-
before: ssmMiddlewareBefore
|
|
142
|
-
};
|
|
143
|
-
};
|
|
144
|
-
const _default = ssmMiddleware;
|
|
145
|
-
|