@friggframework/serverless-plugin 2.0.0--canary.397.155fecd.0 → 2.0.0--canary.398.e2147f7.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 (3) hide show
  1. package/index.js +140 -0
  2. package/index.test.js +494 -0
  3. package/package.json +2 -2
package/index.js CHANGED
@@ -1,16 +1,31 @@
1
1
  const { spawn } = require("child_process");
2
+ const { BuildTimeDiscovery } = require("@friggframework/devtools/infrastructure/build-time-discovery");
2
3
 
4
+ /**
5
+ * Frigg Serverless Plugin - Handles AWS discovery and local development setup
6
+ */
3
7
  class FriggServerlessPlugin {
8
+ /**
9
+ * Creates an instance of FriggServerlessPlugin
10
+ * @param {Object} serverless - Serverless framework instance
11
+ * @param {Object} options - Plugin options
12
+ */
4
13
  constructor(serverless, options) {
5
14
  this.serverless = serverless;
6
15
  this.options = options;
7
16
  this.provider = serverless.getProvider("aws");
8
17
  this.hooks = {
9
18
  initialize: () => this.init(),
19
+ "before:package:initialize": () => this.beforePackageInitialize(),
10
20
  "after:package:package": () => this.afterPackage(),
11
21
  "before:deploy:deploy": () => this.beforeDeploy(),
12
22
  };
13
23
  }
24
+ /**
25
+ * Asynchronous initialization for offline mode
26
+ * Creates SQS queues in localstack for local development
27
+ * @returns {Promise<void>}
28
+ */
14
29
  async asyncInit() {
15
30
  this.serverless.cli.log("Initializing Frigg Serverless Plugin...");
16
31
  console.log("Hello from Frigg Serverless Plugin!");
@@ -83,7 +98,129 @@ class FriggServerlessPlugin {
83
98
  console.log("Running in online mode, doing nothing");
84
99
  }
85
100
  }
101
+
102
+ /**
103
+ * Hook that runs before serverless package initialization
104
+ * Performs AWS resource discovery if needed
105
+ * @returns {Promise<void>}
106
+ */
107
+ async beforePackageInitialize() {
108
+ this.serverless.cli.log("Running Frigg AWS discovery...");
109
+
110
+ try {
111
+ // Check if we need AWS discovery based on the service configuration
112
+ const service = this.serverless.service;
113
+ const needsDiscovery = this.checkIfDiscoveryNeeded(service);
114
+
115
+ if (!needsDiscovery) {
116
+ this.serverless.cli.log("No AWS discovery needed for this configuration");
117
+ return;
118
+ }
119
+
120
+ // Get region from serverless configuration
121
+ const region = service.provider?.region || process.env.AWS_REGION || 'us-east-1';
122
+
123
+ // Create mock app definition from serverless service
124
+ const appDefinition = this.createAppDefinitionFromService(service);
125
+
126
+ // Run AWS discovery
127
+ const discovery = new BuildTimeDiscovery(region);
128
+ const resources = await discovery.preBuildHook(appDefinition, region);
129
+
130
+ if (resources) {
131
+ this.serverless.cli.log("AWS discovery completed successfully");
132
+ // Environment variables are already set by preBuildHook
133
+ }
134
+
135
+ } catch (error) {
136
+ this.serverless.cli.log("AWS discovery failed, continuing with deployment...");
137
+ console.warn("AWS Discovery Error:", error.message);
138
+
139
+ // Set fallback values to prevent deployment failures
140
+ const fallbackEnvVars = {
141
+ AWS_DISCOVERY_VPC_ID: 'vpc-fallback',
142
+ AWS_DISCOVERY_SECURITY_GROUP_ID: 'sg-fallback',
143
+ AWS_DISCOVERY_SUBNET_ID_1: 'subnet-fallback-1',
144
+ AWS_DISCOVERY_SUBNET_ID_2: 'subnet-fallback-2',
145
+ AWS_DISCOVERY_ROUTE_TABLE_ID: 'rtb-fallback',
146
+ AWS_DISCOVERY_KMS_KEY_ID: 'arn:aws:kms:*:*:key/*'
147
+ };
148
+
149
+ Object.assign(process.env, fallbackEnvVars);
150
+ this.serverless.cli.log("Using fallback values for AWS resources");
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Check if AWS discovery is needed based on service configuration
156
+ * @param {Object} service - Serverless service configuration
157
+ * @returns {boolean} True if discovery is needed, false otherwise
158
+ */
159
+ checkIfDiscoveryNeeded(service) {
160
+ // Check if VPC configuration is present
161
+ if (service.provider?.vpc) {
162
+ return true;
163
+ }
164
+
165
+ // Check if KMS grants plugin is present
166
+ if (service.plugins?.includes('serverless-kms-grants')) {
167
+ return true;
168
+ }
169
+
170
+ // Check if lambda layers are configured (SSM)
171
+ if (service.provider?.layers && service.provider.layers.length > 0) {
172
+ return true;
173
+ }
174
+
175
+ // Check for AWS discovery environment variable references
176
+ const serviceString = JSON.stringify(service);
177
+ if (serviceString.includes('AWS_DISCOVERY_')) {
178
+ return true;
179
+ }
180
+
181
+ return false;
182
+ }
183
+
184
+ /**
185
+ * Create a mock app definition from serverless service configuration
186
+ * @param {Object} service - Serverless service configuration
187
+ * @returns {Object} App definition object with vpc, encryption, and ssm configuration
188
+ */
189
+ createAppDefinitionFromService(service) {
190
+ // Create a mock app definition from serverless service configuration
191
+ const appDefinition = {
192
+ integrations: [],
193
+ vpc: {},
194
+ encryption: {},
195
+ ssm: {}
196
+ };
197
+
198
+ // Check for VPC configuration
199
+ if (service.provider?.vpc) {
200
+ appDefinition.vpc.enable = true;
201
+ }
202
+
203
+ // Check for KMS configuration
204
+ if (service.plugins?.includes('serverless-kms-grants')) {
205
+ appDefinition.encryption.useDefaultKMSForFieldLevelEncryption = true;
206
+ }
207
+
208
+ // Check for SSM configuration (lambda layers)
209
+ if (service.provider?.layers && service.provider.layers.some(layer =>
210
+ typeof layer === 'string' && layer.includes('AWS-Parameters-and-Secrets-Lambda-Extension'))) {
211
+ appDefinition.ssm.enable = true;
212
+ }
213
+
214
+ return appDefinition;
215
+ }
216
+
217
+ /**
218
+ * Initialization hook (currently empty)
219
+ */
86
220
  init() {}
221
+ /**
222
+ * Hook that runs after serverless package
223
+ */
87
224
  afterPackage() {
88
225
  console.log("After package hook called");
89
226
  // // const queues = Object.keys(infrastructure.custom)
@@ -123,6 +260,9 @@ class FriggServerlessPlugin {
123
260
  // // });
124
261
  // });
125
262
  }
263
+ /**
264
+ * Hook that runs before serverless deploy
265
+ */
126
266
  beforeDeploy() {
127
267
  console.log("Before deploy hook called");
128
268
  }
package/index.test.js ADDED
@@ -0,0 +1,494 @@
1
+ const FriggServerlessPlugin = require('./index');
2
+ const { BuildTimeDiscovery } = require('@friggframework/devtools/infrastructure/build-time-discovery');
3
+
4
+ // Mock dependencies
5
+ jest.mock('@friggframework/devtools/infrastructure/build-time-discovery');
6
+ jest.mock('aws-sdk');
7
+
8
+ describe('FriggServerlessPlugin', () => {
9
+ let plugin;
10
+ let mockServerless;
11
+ let mockOptions;
12
+ let mockBuildTimeDiscovery;
13
+ const originalEnv = process.env;
14
+
15
+ beforeEach(() => {
16
+ // Mock BuildTimeDiscovery
17
+ mockBuildTimeDiscovery = {
18
+ preBuildHook: jest.fn()
19
+ };
20
+ BuildTimeDiscovery.mockImplementation(() => mockBuildTimeDiscovery);
21
+
22
+ // Mock serverless object
23
+ mockServerless = {
24
+ cli: {
25
+ log: jest.fn()
26
+ },
27
+ service: {
28
+ provider: {
29
+ name: 'aws',
30
+ region: 'us-east-1'
31
+ },
32
+ plugins: [],
33
+ custom: {},
34
+ functions: {}
35
+ },
36
+ processedInput: {
37
+ commands: []
38
+ },
39
+ getProvider: jest.fn(() => ({})),
40
+ extendConfiguration: jest.fn()
41
+ };
42
+
43
+ mockOptions = {
44
+ stage: 'test'
45
+ };
46
+
47
+ plugin = new FriggServerlessPlugin(mockServerless, mockOptions);
48
+
49
+ // Reset environment
50
+ process.env = { ...originalEnv };
51
+
52
+ jest.clearAllMocks();
53
+ });
54
+
55
+ afterEach(() => {
56
+ process.env = originalEnv;
57
+ });
58
+
59
+ describe('constructor', () => {
60
+ it('should initialize plugin with correct hooks', () => {
61
+ expect(plugin.serverless).toBe(mockServerless);
62
+ expect(plugin.options).toBe(mockOptions);
63
+ expect(plugin.hooks).toEqual({
64
+ initialize: expect.any(Function),
65
+ 'before:package:initialize': expect.any(Function),
66
+ 'after:package:package': expect.any(Function),
67
+ 'before:deploy:deploy': expect.any(Function)
68
+ });
69
+ });
70
+
71
+ it('should get AWS provider from serverless', () => {
72
+ expect(mockServerless.getProvider).toHaveBeenCalledWith('aws');
73
+ });
74
+ });
75
+
76
+ describe('beforePackageInitialize', () => {
77
+ it('should run AWS discovery when VPC is configured', async () => {
78
+ mockServerless.service.provider.vpc = '${self:custom.vpc.${self:provider.stage}}';
79
+ const mockResources = {
80
+ defaultVpcId: 'vpc-12345678',
81
+ defaultKmsKeyId: 'arn:aws:kms:us-east-1:123456789012:key/12345678'
82
+ };
83
+ mockBuildTimeDiscovery.preBuildHook.mockResolvedValue(mockResources);
84
+
85
+ await plugin.beforePackageInitialize();
86
+
87
+ expect(mockBuildTimeDiscovery.preBuildHook).toHaveBeenCalledWith(
88
+ expect.objectContaining({
89
+ vpc: { enable: true }
90
+ }),
91
+ 'us-east-1'
92
+ );
93
+ expect(mockServerless.cli.log).toHaveBeenCalledWith('AWS discovery completed successfully');
94
+ });
95
+
96
+ it('should run AWS discovery when KMS grants plugin is present', async () => {
97
+ mockServerless.service.plugins = ['serverless-kms-grants'];
98
+ const mockResources = {
99
+ defaultKmsKeyId: 'arn:aws:kms:us-east-1:123456789012:key/12345678'
100
+ };
101
+ mockBuildTimeDiscovery.preBuildHook.mockResolvedValue(mockResources);
102
+
103
+ await plugin.beforePackageInitialize();
104
+
105
+ expect(mockBuildTimeDiscovery.preBuildHook).toHaveBeenCalledWith(
106
+ expect.objectContaining({
107
+ encryption: { useDefaultKMSForFieldLevelEncryption: true }
108
+ }),
109
+ 'us-east-1'
110
+ );
111
+ });
112
+
113
+ it('should run AWS discovery when lambda layers are configured', async () => {
114
+ mockServerless.service.provider.layers = [
115
+ 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11'
116
+ ];
117
+ const mockResources = {
118
+ defaultVpcId: 'vpc-12345678'
119
+ };
120
+ mockBuildTimeDiscovery.preBuildHook.mockResolvedValue(mockResources);
121
+
122
+ await plugin.beforePackageInitialize();
123
+
124
+ expect(mockBuildTimeDiscovery.preBuildHook).toHaveBeenCalledWith(
125
+ expect.objectContaining({
126
+ ssm: { enable: true }
127
+ }),
128
+ 'us-east-1'
129
+ );
130
+ });
131
+
132
+ it('should run AWS discovery when AWS_DISCOVERY_ environment variables are referenced', async () => {
133
+ mockServerless.service.custom.vpc = {
134
+ securityGroupIds: ['${env:AWS_DISCOVERY_SECURITY_GROUP_ID}']
135
+ };
136
+ const mockResources = {
137
+ defaultVpcId: 'vpc-12345678'
138
+ };
139
+ mockBuildTimeDiscovery.preBuildHook.mockResolvedValue(mockResources);
140
+
141
+ await plugin.beforePackageInitialize();
142
+
143
+ expect(mockBuildTimeDiscovery.preBuildHook).toHaveBeenCalled();
144
+ });
145
+
146
+ it('should skip discovery when no AWS discovery features are needed', async () => {
147
+ await plugin.beforePackageInitialize();
148
+
149
+ expect(mockBuildTimeDiscovery.preBuildHook).not.toHaveBeenCalled();
150
+ expect(mockServerless.cli.log).toHaveBeenCalledWith('No AWS discovery needed for this configuration');
151
+ });
152
+
153
+ it('should use custom region from serverless configuration', async () => {
154
+ mockServerless.service.provider.region = 'eu-west-1';
155
+ mockServerless.service.provider.vpc = '${self:custom.vpc}';
156
+ mockBuildTimeDiscovery.preBuildHook.mockResolvedValue({});
157
+
158
+ await plugin.beforePackageInitialize();
159
+
160
+ expect(mockBuildTimeDiscovery.preBuildHook).toHaveBeenCalledWith(
161
+ expect.any(Object),
162
+ 'eu-west-1'
163
+ );
164
+ });
165
+
166
+ it('should use AWS_REGION environment variable when region not in config', async () => {
167
+ process.env.AWS_REGION = 'ap-southeast-1';
168
+ delete mockServerless.service.provider.region;
169
+ mockServerless.service.provider.vpc = '${self:custom.vpc}';
170
+ mockBuildTimeDiscovery.preBuildHook.mockResolvedValue({});
171
+
172
+ await plugin.beforePackageInitialize();
173
+
174
+ expect(mockBuildTimeDiscovery.preBuildHook).toHaveBeenCalledWith(
175
+ expect.any(Object),
176
+ 'ap-southeast-1'
177
+ );
178
+ });
179
+
180
+ it('should fall back to us-east-1 when no region specified', async () => {
181
+ delete mockServerless.service.provider.region;
182
+ delete process.env.AWS_REGION;
183
+ mockServerless.service.provider.vpc = '${self:custom.vpc}';
184
+ mockBuildTimeDiscovery.preBuildHook.mockResolvedValue({});
185
+
186
+ await plugin.beforePackageInitialize();
187
+
188
+ expect(mockBuildTimeDiscovery.preBuildHook).toHaveBeenCalledWith(
189
+ expect.any(Object),
190
+ 'us-east-1'
191
+ );
192
+ });
193
+
194
+ it('should handle discovery failure gracefully with fallback values', async () => {
195
+ mockServerless.service.provider.vpc = '${self:custom.vpc}';
196
+ const error = new Error('AWS discovery failed');
197
+ mockBuildTimeDiscovery.preBuildHook.mockRejectedValue(error);
198
+
199
+ await plugin.beforePackageInitialize();
200
+
201
+ expect(mockServerless.cli.log).toHaveBeenCalledWith('AWS discovery failed, continuing with deployment...');
202
+ expect(mockServerless.cli.log).toHaveBeenCalledWith('Using fallback values for AWS resources');
203
+
204
+ // Check that fallback environment variables are set
205
+ expect(process.env.AWS_DISCOVERY_VPC_ID).toBe('vpc-fallback');
206
+ expect(process.env.AWS_DISCOVERY_SECURITY_GROUP_ID).toBe('sg-fallback');
207
+ expect(process.env.AWS_DISCOVERY_SUBNET_ID_1).toBe('subnet-fallback-1');
208
+ expect(process.env.AWS_DISCOVERY_SUBNET_ID_2).toBe('subnet-fallback-2');
209
+ expect(process.env.AWS_DISCOVERY_ROUTE_TABLE_ID).toBe('rtb-fallback');
210
+ expect(process.env.AWS_DISCOVERY_KMS_KEY_ID).toBe('arn:aws:kms:*:*:key/*');
211
+ });
212
+
213
+ it('should not set environment variables when discovery returns null', async () => {
214
+ mockServerless.service.provider.vpc = '${self:custom.vpc}';
215
+ mockBuildTimeDiscovery.preBuildHook.mockResolvedValue(null);
216
+
217
+ await plugin.beforePackageInitialize();
218
+
219
+ expect(process.env.AWS_DISCOVERY_VPC_ID).toBeUndefined();
220
+ });
221
+ });
222
+
223
+ describe('checkIfDiscoveryNeeded', () => {
224
+ it('should return true when VPC is configured', () => {
225
+ const service = {
226
+ provider: {
227
+ vpc: '${self:custom.vpc}'
228
+ }
229
+ };
230
+
231
+ const result = plugin.checkIfDiscoveryNeeded(service);
232
+
233
+ expect(result).toBe(true);
234
+ });
235
+
236
+ it('should return true when serverless-kms-grants plugin is present', () => {
237
+ const service = {
238
+ provider: {},
239
+ plugins: ['serverless-kms-grants']
240
+ };
241
+
242
+ const result = plugin.checkIfDiscoveryNeeded(service);
243
+
244
+ expect(result).toBe(true);
245
+ });
246
+
247
+ it('should return true when lambda layers are configured', () => {
248
+ const service = {
249
+ provider: {
250
+ layers: ['arn:aws:lambda:us-east-1:123:layer:test:1']
251
+ }
252
+ };
253
+
254
+ const result = plugin.checkIfDiscoveryNeeded(service);
255
+
256
+ expect(result).toBe(true);
257
+ });
258
+
259
+ it('should return true when AWS_DISCOVERY_ environment variables are referenced', () => {
260
+ const service = {
261
+ provider: {},
262
+ custom: {
263
+ vpc: {
264
+ securityGroupIds: ['${env:AWS_DISCOVERY_SECURITY_GROUP_ID}']
265
+ }
266
+ }
267
+ };
268
+
269
+ const result = plugin.checkIfDiscoveryNeeded(service);
270
+
271
+ expect(result).toBe(true);
272
+ });
273
+
274
+ it('should return false when no discovery features are present', () => {
275
+ const service = {
276
+ provider: {},
277
+ plugins: ['serverless-offline']
278
+ };
279
+
280
+ const result = plugin.checkIfDiscoveryNeeded(service);
281
+
282
+ expect(result).toBe(false);
283
+ });
284
+ });
285
+
286
+ describe('createAppDefinitionFromService', () => {
287
+ it('should create app definition with VPC enabled when VPC is configured', () => {
288
+ const service = {
289
+ provider: {
290
+ vpc: '${self:custom.vpc}'
291
+ }
292
+ };
293
+
294
+ const result = plugin.createAppDefinitionFromService(service);
295
+
296
+ expect(result.vpc.enable).toBe(true);
297
+ });
298
+
299
+ it('should create app definition with encryption enabled when KMS grants plugin is present', () => {
300
+ const service = {
301
+ plugins: ['serverless-kms-grants']
302
+ };
303
+
304
+ const result = plugin.createAppDefinitionFromService(service);
305
+
306
+ expect(result.encryption.useDefaultKMSForFieldLevelEncryption).toBe(true);
307
+ });
308
+
309
+ it('should create app definition with SSM enabled when lambda layers include AWS extension', () => {
310
+ const service = {
311
+ provider: {
312
+ layers: [
313
+ 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11',
314
+ 'arn:aws:lambda:us-east-1:123:layer:other:1'
315
+ ]
316
+ }
317
+ };
318
+
319
+ const result = plugin.createAppDefinitionFromService(service);
320
+
321
+ expect(result.ssm.enable).toBe(true);
322
+ });
323
+
324
+ it('should create app definition with all features enabled', () => {
325
+ const service = {
326
+ provider: {
327
+ vpc: '${self:custom.vpc}',
328
+ layers: ['arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11']
329
+ },
330
+ plugins: ['serverless-kms-grants']
331
+ };
332
+
333
+ const result = plugin.createAppDefinitionFromService(service);
334
+
335
+ expect(result.vpc.enable).toBe(true);
336
+ expect(result.encryption.useDefaultKMSForFieldLevelEncryption).toBe(true);
337
+ expect(result.ssm.enable).toBe(true);
338
+ });
339
+
340
+ it('should create minimal app definition when no features are configured', () => {
341
+ const service = {
342
+ provider: {}
343
+ };
344
+
345
+ const result = plugin.createAppDefinitionFromService(service);
346
+
347
+ expect(result).toEqual({
348
+ integrations: [],
349
+ vpc: {},
350
+ encryption: {},
351
+ ssm: {}
352
+ });
353
+ });
354
+ });
355
+
356
+ describe('asyncInit (offline mode)', () => {
357
+ beforeEach(() => {
358
+ // Mock AWS SDK
359
+ const mockSQS = {
360
+ createQueue: jest.fn()
361
+ };
362
+
363
+ jest.doMock('aws-sdk', () => ({
364
+ SQS: jest.fn(() => mockSQS),
365
+ config: {
366
+ update: jest.fn()
367
+ }
368
+ }));
369
+
370
+ mockServerless.service.custom = {
371
+ TestQueue: 'test-queue-name',
372
+ AnotherQueue: 'another-queue-name'
373
+ };
374
+
375
+ mockServerless.service.provider.environment = {
376
+ TEST_QUEUE_URL: { Ref: 'TestQueue' },
377
+ ANOTHER_QUEUE_URL: { Ref: 'AnotherQueue' },
378
+ NORMAL_VAR: 'normal-value'
379
+ };
380
+ });
381
+
382
+ it('should create queues in offline mode', async () => {
383
+ mockServerless.processedInput.commands = ['offline'];
384
+
385
+ const AWS = require('aws-sdk');
386
+ const mockSQS = new AWS.SQS();
387
+ mockSQS.createQueue.mockImplementation((params, callback) => {
388
+ callback(null, { QueueUrl: `http://localhost:4566/000000000000/${params.QueueName}` });
389
+ });
390
+
391
+ await plugin.asyncInit();
392
+
393
+ expect(AWS.config.update).toHaveBeenCalledWith({
394
+ region: 'us-east-1',
395
+ endpoint: 'localhost:4566'
396
+ });
397
+
398
+ expect(mockSQS.createQueue).toHaveBeenCalledWith(
399
+ { QueueName: 'test-queue-name' },
400
+ expect.any(Function)
401
+ );
402
+
403
+ expect(mockSQS.createQueue).toHaveBeenCalledWith(
404
+ { QueueName: 'another-queue-name' },
405
+ expect.any(Function)
406
+ );
407
+
408
+ expect(mockServerless.extendConfiguration).toHaveBeenCalled();
409
+ });
410
+
411
+ it('should skip queue creation in online mode', async () => {
412
+ mockServerless.processedInput.commands = ['deploy'];
413
+
414
+ await plugin.asyncInit();
415
+
416
+ const AWS = require('aws-sdk');
417
+ expect(AWS.config.update).not.toHaveBeenCalled();
418
+ });
419
+
420
+ it('should handle queue creation errors', async () => {
421
+ mockServerless.processedInput.commands = ['offline'];
422
+
423
+ const AWS = require('aws-sdk');
424
+ const mockSQS = new AWS.SQS();
425
+ mockSQS.createQueue.mockImplementation((params, callback) => {
426
+ callback(new Error('Queue creation failed'));
427
+ });
428
+
429
+ await expect(plugin.asyncInit()).rejects.toThrow('Queue creation failed');
430
+ });
431
+ });
432
+
433
+ describe('hook methods', () => {
434
+ it('should have init method', () => {
435
+ expect(plugin.init).toBeDefined();
436
+ expect(typeof plugin.init).toBe('function');
437
+ });
438
+
439
+ it('should have afterPackage method', () => {
440
+ expect(plugin.afterPackage).toBeDefined();
441
+ expect(typeof plugin.afterPackage).toBe('function');
442
+
443
+ // Test that it logs correctly
444
+ const consoleSpy = jest.spyOn(console, 'log');
445
+ plugin.afterPackage();
446
+ expect(consoleSpy).toHaveBeenCalledWith('After package hook called');
447
+ consoleSpy.mockRestore();
448
+ });
449
+
450
+ it('should have beforeDeploy method', () => {
451
+ expect(plugin.beforeDeploy).toBeDefined();
452
+ expect(typeof plugin.beforeDeploy).toBe('function');
453
+
454
+ // Test that it logs correctly
455
+ const consoleSpy = jest.spyOn(console, 'log');
456
+ plugin.beforeDeploy();
457
+ expect(consoleSpy).toHaveBeenCalledWith('Before deploy hook called');
458
+ consoleSpy.mockRestore();
459
+ });
460
+ });
461
+
462
+ describe('integration with BuildTimeDiscovery', () => {
463
+ it('should pass correct region to BuildTimeDiscovery constructor', async () => {
464
+ mockServerless.service.provider.region = 'eu-central-1';
465
+ mockServerless.service.provider.vpc = '${self:custom.vpc}';
466
+ mockBuildTimeDiscovery.preBuildHook.mockResolvedValue({});
467
+
468
+ await plugin.beforePackageInitialize();
469
+
470
+ expect(BuildTimeDiscovery).toHaveBeenCalledWith('eu-central-1');
471
+ });
472
+
473
+ it('should pass correct app definition to preBuildHook', async () => {
474
+ mockServerless.service.provider.vpc = '${self:custom.vpc}';
475
+ mockServerless.service.plugins = ['serverless-kms-grants'];
476
+ mockServerless.service.provider.layers = [
477
+ 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11'
478
+ ];
479
+ mockBuildTimeDiscovery.preBuildHook.mockResolvedValue({});
480
+
481
+ await plugin.beforePackageInitialize();
482
+
483
+ expect(mockBuildTimeDiscovery.preBuildHook).toHaveBeenCalledWith(
484
+ {
485
+ integrations: [],
486
+ vpc: { enable: true },
487
+ encryption: { useDefaultKMSForFieldLevelEncryption: true },
488
+ ssm: { enable: true }
489
+ },
490
+ 'us-east-1'
491
+ );
492
+ });
493
+ });
494
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@friggframework/serverless-plugin",
3
- "version": "2.0.0--canary.397.155fecd.0",
3
+ "version": "2.0.0--canary.398.e2147f7.0",
4
4
  "description": "Plugin to help dynamically load frigg resources",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -11,5 +11,5 @@
11
11
  "publishConfig": {
12
12
  "access": "public"
13
13
  },
14
- "gitHead": "155fecdabd27d01d1c1001261e9ec4b824826411"
14
+ "gitHead": "e2147f7f03122a5daa917429ba610c1a7c6ef819"
15
15
  }