serverless-bedrock-agentcore-plugin 0.1.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.
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const naming = require('./naming');
4
+ const tags = require('./tags');
5
+
6
+ module.exports = {
7
+ ...naming,
8
+ ...tags,
9
+ };
@@ -0,0 +1,79 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Generate a resource name following the pattern: {service}-{name}-{stage}
5
+ *
6
+ * @param {string} serviceName - The Serverless service name
7
+ * @param {string} name - The agent/resource name
8
+ * @param {string} stage - The deployment stage
9
+ * @returns {string} The generated resource name
10
+ */
11
+ function getResourceName(serviceName, name, stage) {
12
+ // AgentCore names have pattern: [a-zA-Z][a-zA-Z0-9_]{0,47}
13
+ // Replace hyphens with underscores and ensure it starts with a letter
14
+ const baseName = `${serviceName}_${name}_${stage}`
15
+ .replace(/-/g, '_')
16
+ .replace(/[^a-zA-Z0-9_]/g, '');
17
+
18
+ // Ensure it starts with a letter
19
+ const safeName = /^[a-zA-Z]/.test(baseName) ? baseName : `A${baseName}`;
20
+
21
+ // Truncate to max 48 characters
22
+ return safeName.substring(0, 48);
23
+ }
24
+
25
+ /**
26
+ * Generate a CloudFormation logical ID from the agent name and resource type
27
+ *
28
+ * @param {string} name - The agent name
29
+ * @param {string} resourceType - The resource type (e.g., 'Runtime', 'Memory')
30
+ * @returns {string} The CloudFormation logical ID
31
+ */
32
+ function getLogicalId(name, resourceType) {
33
+ // Convert to PascalCase and remove invalid characters
34
+ const pascalName = name
35
+ .split(/[-_]/)
36
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
37
+ .join('');
38
+
39
+ return `${pascalName}${resourceType}`;
40
+ }
41
+
42
+ /**
43
+ * Generate a CloudFormation logical ID for nested resources
44
+ *
45
+ * @param {string} parentName - The parent resource name
46
+ * @param {string} childName - The child resource name
47
+ * @param {string} resourceType - The resource type
48
+ * @returns {string} The CloudFormation logical ID
49
+ */
50
+ function getNestedLogicalId(parentName, childName, resourceType) {
51
+ const pascalParent = parentName
52
+ .split(/[-_]/)
53
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
54
+ .join('');
55
+
56
+ const pascalChild = childName
57
+ .split(/[-_]/)
58
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
59
+ .join('');
60
+
61
+ return `${pascalParent}${pascalChild}${resourceType}`;
62
+ }
63
+
64
+ /**
65
+ * Sanitize a name for use in CloudFormation
66
+ *
67
+ * @param {string} name - The name to sanitize
68
+ * @returns {string} The sanitized name
69
+ */
70
+ function sanitizeName(name) {
71
+ return name.replace(/[^a-zA-Z0-9]/g, '');
72
+ }
73
+
74
+ module.exports = {
75
+ getResourceName,
76
+ getLogicalId,
77
+ getNestedLogicalId,
78
+ sanitizeName,
79
+ };
@@ -0,0 +1,56 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Merge tags from multiple sources with proper precedence
5
+ *
6
+ * @param {Object} defaultTags - Default tags from custom.agentCore.defaultTags
7
+ * @param {Object} resourceTags - Tags specific to the resource
8
+ * @param {string} serviceName - The Serverless service name
9
+ * @param {string} stage - The deployment stage
10
+ * @param {string} resourceName - The resource name
11
+ * @returns {Object} Merged tags object for CloudFormation
12
+ */
13
+ function mergeTags(defaultTags = {}, resourceTags = {}, serviceName, stage, resourceName) {
14
+ const tags = {
15
+ ...defaultTags,
16
+ ...resourceTags,
17
+ 'serverless:service': serviceName,
18
+ 'serverless:stage': stage,
19
+ 'agentcore:resource': resourceName,
20
+ };
21
+
22
+ return tags;
23
+ }
24
+
25
+ /**
26
+ * Convert tags object to CloudFormation Tags array format
27
+ *
28
+ * @param {Object} tags - Tags object with key-value pairs
29
+ * @returns {Array} Array of {Key, Value} objects for CloudFormation
30
+ */
31
+ function tagsToCloudFormationArray(tags) {
32
+ return Object.entries(tags).map(([Key, Value]) => ({
33
+ Key,
34
+ Value: String(Value),
35
+ }));
36
+ }
37
+
38
+ /**
39
+ * Convert CloudFormation Tags array to object format
40
+ *
41
+ * @param {Array} tagsArray - Array of {Key, Value} objects
42
+ * @returns {Object} Tags object with key-value pairs
43
+ */
44
+ function cloudFormationArrayToTags(tagsArray) {
45
+ return tagsArray.reduce((acc, { Key, Value }) => {
46
+ acc[Key] = Value;
47
+
48
+ return acc;
49
+ }, {});
50
+ }
51
+
52
+ module.exports = {
53
+ mergeTags,
54
+ tagsToCloudFormationArray,
55
+ cloudFormationArrayToTags,
56
+ };
@@ -0,0 +1,250 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Define JSON Schema validation for the 'agents' top-level configuration
5
+ *
6
+ * @param {Object} serverless - The Serverless instance
7
+ */
8
+ function defineAgentsSchema(serverless) {
9
+ // Define the 'agents' top-level property
10
+ serverless.configSchemaHandler.defineTopLevelProperty('agents', {
11
+ type: 'object',
12
+ additionalProperties: {
13
+ type: 'object',
14
+ properties: {
15
+ type: {
16
+ type: 'string',
17
+ enum: ['runtime', 'memory', 'gateway', 'browser', 'codeInterpreter', 'workloadIdentity'],
18
+ },
19
+ description: {
20
+ type: 'string',
21
+ minLength: 1,
22
+ maxLength: 1200,
23
+ },
24
+ tags: {
25
+ type: 'object',
26
+ additionalProperties: { type: 'string' },
27
+ },
28
+ roleArn: {
29
+ type: 'string',
30
+ pattern: '^arn:aws(-[^:]+)?:iam::([0-9]{12})?:role/.+$',
31
+ },
32
+
33
+ // Runtime-specific properties
34
+ artifact: {
35
+ type: 'object',
36
+ properties: {
37
+ containerImage: { type: 'string' },
38
+ s3: {
39
+ type: 'object',
40
+ properties: {
41
+ bucket: { type: 'string' },
42
+ key: { type: 'string' },
43
+ },
44
+ required: ['bucket', 'key'],
45
+ },
46
+ },
47
+ },
48
+ protocol: {
49
+ type: 'string',
50
+ enum: ['HTTP', 'MCP', 'A2A'],
51
+ },
52
+ environment: {
53
+ type: 'object',
54
+ additionalProperties: { type: 'string' },
55
+ },
56
+ network: {
57
+ type: 'object',
58
+ properties: {
59
+ networkMode: {
60
+ type: 'string',
61
+ enum: ['PUBLIC', 'VPC'],
62
+ },
63
+ vpcConfig: {
64
+ type: 'object',
65
+ properties: {
66
+ subnetIds: {
67
+ type: 'array',
68
+ items: { type: 'string' },
69
+ },
70
+ securityGroupIds: {
71
+ type: 'array',
72
+ items: { type: 'string' },
73
+ },
74
+ },
75
+ },
76
+ },
77
+ },
78
+ authorizer: {
79
+ type: 'object',
80
+ properties: {
81
+ type: {
82
+ type: 'string',
83
+ enum: ['CUSTOM_JWT', 'AWS_IAM', 'NONE'],
84
+ },
85
+ jwtConfiguration: {
86
+ type: 'object',
87
+ properties: {
88
+ issuer: { type: 'string' },
89
+ audience: {
90
+ type: 'array',
91
+ items: { type: 'string' },
92
+ },
93
+ },
94
+ },
95
+ },
96
+ },
97
+ lifecycle: {
98
+ type: 'object',
99
+ properties: {
100
+ idleTimeout: { type: 'number' },
101
+ maxConcurrency: { type: 'number' },
102
+ },
103
+ },
104
+ endpoints: {
105
+ type: 'array',
106
+ items: {
107
+ type: 'object',
108
+ properties: {
109
+ name: { type: 'string' },
110
+ version: { type: 'string' },
111
+ description: { type: 'string' },
112
+ },
113
+ },
114
+ },
115
+
116
+ // Memory-specific properties
117
+ eventExpiryDuration: {
118
+ type: 'number',
119
+ minimum: 7,
120
+ maximum: 365,
121
+ },
122
+ encryptionKeyArn: {
123
+ type: 'string',
124
+ },
125
+ strategies: {
126
+ type: 'array',
127
+ items: {
128
+ type: 'object',
129
+ properties: {
130
+ type: {
131
+ type: 'string',
132
+ enum: ['semantic', 'userPreference', 'summary', 'custom'],
133
+ },
134
+ name: { type: 'string' },
135
+ namespaces: {
136
+ type: 'array',
137
+ items: { type: 'string' },
138
+ },
139
+ configuration: {
140
+ type: 'object',
141
+ },
142
+ },
143
+ required: ['type', 'name'],
144
+ },
145
+ },
146
+
147
+ // Gateway-specific properties
148
+ authorizerType: {
149
+ type: 'string',
150
+ enum: ['AWS_IAM', 'CUSTOM_JWT'],
151
+ },
152
+ protocolType: {
153
+ type: 'string',
154
+ enum: ['MCP'],
155
+ },
156
+ authorizerConfiguration: {
157
+ type: 'object',
158
+ properties: {
159
+ allowedAudiences: {
160
+ type: 'array',
161
+ items: { type: 'string' },
162
+ },
163
+ allowedClients: {
164
+ type: 'array',
165
+ items: { type: 'string' },
166
+ },
167
+ allowedIssuers: {
168
+ type: 'array',
169
+ items: { type: 'string' },
170
+ },
171
+ },
172
+ },
173
+ kmsKeyArn: {
174
+ type: 'string',
175
+ },
176
+ targets: {
177
+ type: 'array',
178
+ items: {
179
+ type: 'object',
180
+ properties: {
181
+ name: { type: 'string' },
182
+ type: {
183
+ type: 'string',
184
+ enum: ['openapi', 'lambda', 'smithy'],
185
+ },
186
+ description: { type: 'string' },
187
+ functionArn: { type: 'string' },
188
+ functionName: { type: 'string' },
189
+ s3: {
190
+ type: 'object',
191
+ properties: {
192
+ bucket: { type: 'string' },
193
+ key: { type: 'string' },
194
+ },
195
+ },
196
+ credentialProvider: {
197
+ type: 'object',
198
+ properties: {
199
+ type: {
200
+ type: 'string',
201
+ enum: ['GATEWAY_IAM_ROLE', 'OAUTH', 'API_KEY'],
202
+ },
203
+ oauthConfig: {
204
+ type: 'object',
205
+ properties: {
206
+ secretArn: { type: 'string' },
207
+ tokenUrl: { type: 'string' },
208
+ scopes: {
209
+ type: 'array',
210
+ items: { type: 'string' },
211
+ },
212
+ },
213
+ },
214
+ apiKeyConfig: {
215
+ type: 'object',
216
+ properties: {
217
+ secretArn: { type: 'string' },
218
+ },
219
+ },
220
+ },
221
+ },
222
+ },
223
+ required: ['name'],
224
+ },
225
+ },
226
+ },
227
+ required: ['type'],
228
+ },
229
+ });
230
+
231
+ // Define custom.agentCore configuration
232
+ serverless.configSchemaHandler.defineCustomProperties({
233
+ type: 'object',
234
+ properties: {
235
+ agentCore: {
236
+ type: 'object',
237
+ properties: {
238
+ defaultTags: {
239
+ type: 'object',
240
+ additionalProperties: { type: 'string' },
241
+ },
242
+ },
243
+ },
244
+ },
245
+ });
246
+ }
247
+
248
+ module.exports = {
249
+ defineAgentsSchema,
250
+ };